home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / CONVERS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-18  |  120.7 KB  |  4,848 lines

  1. /* convers server - based on conversd written by DK5SG
  2.  * ported to WNOS by DB3FL - 9109xx/9110xx
  3.  * ported to NOS by PE1NMB - 920120
  4.  * Mods by PA0GRI
  5.  * Cleanup, and additional mods by WG7J
  6.  * Major additions, rewrites, enhancements by KO4KS
  7.  */
  8.  
  9. #include "global.h"
  10. #ifdef CONVERS
  11. #include "commands.h"
  12. #include "ctype.h"
  13. #ifdef    UNIX
  14. #include <sys/stat.h>
  15. #endif
  16. #ifdef MSDOS
  17. #include <io.h>
  18. #else
  19. #include <time.h>
  20. #include "session.h"
  21. #endif
  22. #ifdef MAILBOX
  23. #include "mailbox.h"
  24. #endif
  25. #include "files.h"
  26. #ifdef LZW
  27. #include "lzw.h"
  28. #endif
  29. #include "x.h"
  30. #include "domain.h"
  31.  
  32. #if !defined(_lint)
  33. static char rcsid[] OPTIONAL = "$Id: convers.c,v 1.33 1997/08/19 01:19:22 root Exp root $";
  34. #endif
  35.  
  36. extern char stars[];
  37.  
  38. static int conv_rand (void);
  39.  
  40. #pragma option -zEMYFAR
  41.  
  42. #define    LINK    1
  43. #define space
  44.  
  45.  
  46. #if defined(LZW)
  47. void togglelzw (int soc, int mode);
  48. #endif
  49.  
  50.  
  51. int32 CT4init = 7200;            /* 2 hours default */
  52. static int CChannel = 0;        /* default entry to channel 0 */
  53. static int HMaxQ = 6 * 1024L;
  54. static int UMaxQ = 3 * 1024L;
  55. int Sconv = -1;
  56. static int ConvNet0 = 0;
  57. static int ConvHeader = 0;
  58. static int TimeStamp = 0;
  59. extern char shortversion[];
  60. extern char *Months[];        /*lint !e15 * in smtpserv.c */
  61. static int Conv_mutex = TNOS_MUTEX_UNLOCKED;
  62. static int Group_mutex = TNOS_MUTEX_UNLOCKED;
  63.  
  64. #define PREFIXLEN 10
  65. #define CONVLINELEN   79
  66.  
  67. static const char *suits[] = { "Hearts", "Clubs", "Diamonds", "Spades" };
  68. static const char *cards[] = { "Ace", "Deuce", "Three", "Four", "Five", "Six",
  69.     "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" };
  70.  
  71. #ifdef STATS_USE
  72. long localConfUsers = 0;
  73. #endif
  74.  
  75. int Conflogins = 0;
  76.  
  77. #ifdef space
  78. static char cnumber[] = "*** Channel numbers must be in the range 0..%d.\n";
  79. #else
  80. static char cnumber[] = "* range 0..%d.\n";
  81. #endif
  82.  
  83.  
  84. static char trailer[] = "***\n";
  85. static char noinfo[] = "No additional information available";
  86. static char sysinfoheader[] = "%sSystem Information for: %s - email to sysop@%s\n";
  87. static char msgtext[] = "<*%s*>: %s\n";
  88. static char theysigned[] = "%s%s signed o%s at %s.\n";
  89. static char theyswitched[] = "%s%s switched to channel %d at %s.\n";
  90. static char conversd[] = "conversd";
  91. static char fullstr[] = "%s";
  92. static char fullstrcr[] = "%s\n";
  93. static char sosorry[] = "*** Sorry, ";
  94. static char sorry[] = "%s%s Net on %s %d!\n";
  95. static char busystr[] = "%s'%s' is already a %s!\n";
  96. static char logfilestr[] = "%sLogfile is %sed\n";
  97. static char netcontrolstr[] = "Net Control";
  98. static char privatestr[] = "Closed";
  99. static char clearedstr[] = "cleared";
  100. static char passwordstr[] = "Password";
  101. static char nowchannel[] = "%sNow on %s %d (%d user%s).\n";
  102. static char nicknamestr[] = "%s%s%sset to '%s'.\n";
  103. static char channelstr[] = "Channel";
  104. static char systemstr[] = "SYSTEM";
  105. static char unknownstr[] = "*** Unknown ";
  106. static char unkcmdstr[] = "%scommand '/%s'.%s";
  107. static char nouserstr[] = "%suser!\n";
  108. static char gethelpstr[] = " Type /HELP for help.\n";
  109. static char noopenstr[] = "Can't open '%s'\n";
  110. static char activenetstr[] = "%sActive Net '%s'\n";
  111. static char net2str[] = "%sNet %s %s\n";
  112. static char conferencestr[] = "*** TNOS Conference @ ";
  113. static char namecmdstr[] = "%sPlease login with '/n <call>'\n";
  114. static char nonetstr[] = "%sNo Net!\n";
  115. static char recheckstr[] = "*** Recheck";
  116. static char questionstr[] = "*** Question";
  117. static char nicknmstr[] = "Nickname ";
  118. static char tmstr[] = "Time";
  119. static char userstr[] = "User";
  120. static char hoststr[] = "Host";
  121. static char newuserstr[] = "%sNew user '%s' has entered conference area on channel '%d'";
  122. static char urnotstr[] = "%sYou are not %s\n";
  123. static char urassigned[] = "%s'%s' has assigned you as %s on %s %d\n";
  124. static char wrongchannel[] = "%s%s '%s' not on this %s\n";
  125. static char openminutes[] = "%sMinutes starting at %s\n%sNet '%s' - %s is '%s'\n";
  126. static char closeminutes[] = "%sMinutes ending at %s\n";
  127. static char headerstr[] = "User       Host       Via         Channel  Time Personal\n";
  128. static char userdata[] = "%-10.10s %-10.10s %-11.11s %6d %s %-31.31s\n";
  129. static char summary[] = "%sTNOS Conference Bridge command summary:\n ";
  130. static char extendedsummary[] = "\n%sExtended Remote Commands:\n ";
  131. static char modeis[] = "Mode is: %s\n";
  132. static char acceptstr[] = "Accept";
  133. static char refuse[] = "Refuse";
  134. static char redun[] = "Conf. redundancy timer (sec)";
  135. static char entrystr[] = "Conf. entry channel";
  136. static char givehead[] = "Display login header on connect";
  137. static char allownets[] = "Allow Nets on Channel 0";
  138. static char timestampstr[] = "Timestamp all user messages";
  139. static char maxwaitstr[] = "Re-link max wait (sec)";
  140. static char hostqueuestr[] = "Max. Host Queue (bytes)";
  141. static char userqueuestr[] = "Max. User Queue (bytes)";
  142. static char motdstr[] = "Conference MOTD: %s\n";
  143. static char sysinfostr[] = "SYStem INFOrmation: %s\n";
  144. static char timestampfmt[] = "<*%s:%s*>:";
  145. static char nontimestampfmt[] = "<*%s*>:";
  146. static char timestampfmt2[] = "<%s:%s>:";
  147. static char nontimestampfmt2[] = "<%s>:";
  148. static char alreadyon[] = "%s%s %s is already on this channel.";
  149. static char exitingstr[] = "Exiting %s%s\n";
  150. static char welcome[] = "%s%s%sNet '%s'";
  151. static char welcome2[] = " - %s is '%s'...";
  152. static char welcome3[] = "\n Welcome, %s!\n";
  153. static char welcomeback[] = "%sWelcome back, %s\n";
  154. static char noinvite[] = "%s%s net, only %s can invite\n";
  155. static char nosuchuser[] = "%sNo such user: %s.\n";
  156. static char online[] = "%sThere are %d users online\n";
  157. static char groupsavail[] = "%sThere %s %d group%s available\n";
  158. static char colorstatus[] = "%sCurrently ANSI Color graphics are O%s\n";
  159. static char personalset[] = "%sPersonal data set to: %s\n";
  160. #ifdef ALLSERV
  161. static char quotebanner[] = "*** Quote of the day:\n";
  162. #endif
  163. static char whobanner[] = "%s             %s  %s Personal\n";
  164. static char rollstr[] = "%s'%s' has rolled a %d and a %d for a total of %d! %s";
  165. static char cutstr[] = "%s'%s' has cut the deck and selected the %s of %s! %s";
  166. static char gloghdr[] = "*** Current Check-ins\n";
  167. static char glogstr[] = "    %s     %s         In    %s\n";
  168. static char grouphdr[] = "%sAvailable Groups:\n Channel  Group Name\n =======  ==========\n";
  169.  
  170. #ifdef space
  171. static char youare[] = "%sYou are %son channel %d.\n";
  172. static char amessage[] = "\n*** Message from ";
  173. static char invitetext[] = "%s%s at %s ...\n%sPlease join conference channel %d.\n";
  174. static char mbinvitetext[] = "%s%s at %s ...\n%sPlease type 'CONF %d' to join conference channel %d.\n";
  175. static char responsetext[] = "%sInvitation sent to %s @ %s";
  176. #else
  177. static char youare[] = "%sOn channel %d.\n";
  178. static char amessage[] = "\n*** Msg frm ";
  179. static char invitetext[] = "%s%s at %s ...\n%sPse join ch. %d.\n";
  180. static char mbinvitetext[] = "%s at %s ...\n%sPse hit 'CONF %d' for conference ch. %d.\n";
  181. static char responsetext[] = "%ssent to %s @ %s";
  182. #endif
  183.  
  184. static char hinvi[] = "/\377\200INVI %s %s %d %s\n";
  185. static char uaddstr[] = "/\377\200UADD %s %s %s %d %s\n";
  186. static char bumpstr[] = "/\377\200BUMP %s %d\n";
  187. static char ndatstr[] = "/\377\200NDAT %d %d %d %d %d %s|%s|%s|\n";
  188. static char topicstr[] = "/\377\200TOPI %s %s %ld %d %s\n";
  189. static char quesstr[] = "/\377\200QUES %d %c %s %s\n";
  190. static char umsgstr[] = "/\377\200UMSG %s %s %s\n";
  191. static char cmsgstr[] = "/\377\200CMSG %s %d %s\n";
  192. static char hhoststr[] = "/\377\200HOST %s %s %s\n";
  193. static char huserstr[] = "/\377\200USER %s %s %ld %d %d %s\n";
  194. static char loopstr[] = "/\377\200LOOP %s %s %s\n";
  195. static char SYSCOLORS[] = "0C";
  196. static char TEXTCOLORS[] = "09";
  197. static char INFOCOLORS[] = "0B";
  198.  
  199. #if 0
  200. static char INPUTCOLORS[] = "0F";
  201. #endif
  202.  
  203. static char ff_str[] = "ff";
  204. static char n_str[] = "n";
  205. static char empty[] = "";
  206.  
  207.  
  208. static char myfeatures[] = "dnpu";
  209.  
  210. #define MAXCHANNEL     ((int) 32767)
  211. #ifndef LINELEN
  212. #define LINELEN     256
  213. #endif
  214. #define INBUFLEN    2048
  215. #define MAX_WAITTIME    (60*60*3)
  216. #define NAMELEN 16
  217.  
  218. static long CMaxwait = MAX_WAITTIME;
  219.  
  220.  
  221. struct convection {
  222.     int type;        /* Connection type */
  223. #define CT_UNKNOWN      0
  224. #define CT_USER         1
  225. #define CT_HOST         2
  226. #define CT_CLOSED       3
  227.     char name[NAMELEN + 1];    /* Name of user or host */
  228.     char host[NAMELEN + 1];    /* Name of host where user is logged on */
  229.     char nickname[NAMELEN + 1];    /* Nickname of user */
  230.     char password[NAMELEN + 1];    /* Password of user */
  231.     struct convection *via;    /* Pointer to neighbor host */
  232.     char *data;        /* room for some personal data */
  233.     int channel;        /* Channel number */
  234.     int net;        /* Channel of controlled net */
  235.     time_t nettime;        /* Time entered channel (used by nets) */
  236.     time_t time;        /* Connect time */
  237.     int maxq;        /* Maximum outstanding data before link reset */
  238.     int locked;        /* Set if mesg already sent */
  239.     int fd;            /* Socket descriptor */
  240.     int flags;        /* User flags */
  241. #define CLOSE_SOCK  1
  242. #define USE_SOUND   2
  243. #define CHANGED_INFO 4
  244. #define USE_LZW 8
  245. #define USE_COLOR 16
  246.     char colorset[2];    /* current color set */
  247.     int features;
  248. #define FEATURE_AWAY    1    /* a - "away feature" */
  249. #define FEATURE_FWD     2    /* d - "destination forwarding" */
  250. #define FEATURE_MODES   4    /* m - "channel modes" */
  251. #define FEATURE_LINK    8    /* p - "ping pong link measurement" */
  252. #define FEATURE_UDAT    16    /* u - "udat command extension and user command understood both" */
  253. #define FEATURE_NICK    32    /* n - "TNOS Nickname extensions" */
  254.     /* This buffer is only needed for local users; a lot of space is wasted
  255.      * for users from other hosts (256 bytes per user!). Fixed 930728 - WG7J
  256.      * char ibuf[INBUFLEN];
  257.      */
  258.     char *ibuf;        /* Input buffer */
  259.     char *ibufpt;        /* 2nd buffer pointer, for parsing command line */
  260.     int received;        /* Number of bytes received */
  261.     int xmitted;        /* Number of bytes transmitted */
  262.     int paged;        /* Last channel invited to (paged) */
  263.     struct convection *next;/* Linked list pointer */
  264. };
  265.  
  266.  
  267. #define CM_UNKNOWN    (1 << CT_UNKNOWN)
  268. #define CM_USER        (1 << CT_USER)
  269. #define CM_HOST        (1 << CT_HOST)
  270. #ifndef _lint
  271. #define CM_CLOSED    (1 << CT_CLOSED)
  272. #endif
  273.  
  274. #define NULLCONNECTION    ((struct convection *) 0)
  275.  
  276. static struct convection *convections;
  277.  
  278.  
  279. struct permlink {
  280.     char name[NAMELEN + 1];    /* Name of link */
  281.     char rev[NAMELEN + 1];    /* revision of software (CT_HOST) */
  282.     uint32 addr;        /* address to link to */
  283.     struct convection *convection;    /* Pointer to associated connection */
  284.     time_t statetime;    /* Time of last (dis)connect */
  285.     int tries;        /* Number of connect tries */
  286.     time_t waittime;    /* Time between connect tries */
  287.     time_t retrytime;    /* Time of next connect try */
  288.     time_t testwaittime;    /* Time between tries */
  289.     time_t testnexttime;    /* Time of next test */
  290.     time_t rxtime;        /* rtt by other side */
  291.     time_t txtime;        /* rtt found out by me */
  292.     unsigned short port;    /* port number to connect to */
  293.     int fd;            /* socket descriptor */
  294.     struct permlink *next;    /* Linked list pointer */
  295. };
  296.  
  297. #define NULLPERMLINK ((struct permlink *) 0)
  298.  
  299. static struct permlink *permlinks;
  300.  
  301.  
  302.  
  303. struct filter_link {
  304.     struct filter_link *next;
  305.     uint32 addr;
  306. };
  307.  
  308. #ifndef _lint
  309. #define NULLFL ((struct filter_link *) 0)
  310. #endif
  311.  
  312. static struct filter_link *Filterlinks;
  313. static int FilterMode;
  314.  
  315.  
  316. #ifdef LINK
  317. static struct proc *Linker;
  318. static void connect_permlinks (int a, void *b, void *c);
  319. static void update_permlinks (char *name, struct convection * cp);
  320. #endif
  321.  
  322.  
  323. #if 0
  324. #define NR_PERMLINKS 20        /* MUST be changed, later */
  325. #endif
  326.  
  327. struct destination {
  328.     char name[NAMELEN + 1];    /* destination name */
  329.     char rev[NAMELEN + 1];    /* revision of software (CT_HOST) */
  330.     struct permlink *link;    /* link to this destination */
  331.     long rtt;        /* round trip time to this host */
  332.     long last_sent_rtt;    /* last donwnstream sent rtt */
  333. #if 0
  334.     int downstream[NR_PERMLINKS];    /* all up/downstream times */
  335. #endif
  336.     struct destination *next;    /* a one dimensional list is ok for now :-) */
  337. };
  338.  
  339.  
  340. #define NULLDESTINATION  ((struct destination *) 0)
  341. static struct destination *destinations;
  342.  
  343.  
  344. extern void statlog (const char *buf);
  345. extern const char *displayMBstatus (int state, int issysop);
  346. #ifndef UNIX
  347. extern int colorchange (register const char *input, register char *last);
  348. #endif
  349. static int ShowConfDest (int s, const char *dest, const char *name);
  350. static void update_destinations (struct permlink * p, char *name, long rtt, const char *rev);
  351.  
  352. #ifdef ALLSERV
  353. extern char *getquote (void);
  354. #endif
  355.  
  356. static void conv_randomize (void);
  357. static int conv_random (int num, int base);
  358. static void sysinfo_command (struct convection * cp);
  359. static void h_sysi_command (struct convection * cp);
  360. static void cmdsummary_command (struct convection * cp);
  361. static void personal_command (struct convection * cp);
  362. static void list_command (struct convection * cp);
  363. static void me_command (struct convection * cp);
  364. static void cq_command (struct convection * cp);
  365. static void imsg_command (struct convection * cp);
  366. static void version_command (struct convection * cp);
  367. static void hosts_command (struct convection * cp);
  368. static void nickname_command (struct convection * cp);
  369. static void convcolorchange (struct convection * p, char *str);
  370. static void roll_command (struct convection * cp);
  371. static void cut_command (struct convection * cp);
  372. static void save_personal (struct convection * cp);
  373. static void conv_incom (int s, void *t, void *p);
  374.  
  375. static void free_connection (register struct convection * cp);
  376. static void free_closed_connections (void);
  377. static struct convection *alloc_connection (int fd);
  378. static void check_buffer_overload (void);
  379. static void clear_locks (void);
  380. static void send_sounds (struct convection * p);
  381. static char *timestring (time_t gmt);
  382. static void send_user_change_msg (char *name, char *host, time_t thetime, int oldchannel, int newchannel, char *pers);
  383. static char *formatline (char *prefix, const char *text);
  384. static void send_msg_to_user (const char *fromname, const char *toname, const char *text);
  385. static void send_msg_to_channel (const char *fromname, int channel, const char *text);
  386. static void send_invite_msg (char *fromname, char *toname, int channel, char *msg);
  387. static void time_command (struct convection * cp);
  388. static int onchannel (int channel);
  389. static void mystatus (struct convection * cp, int old);
  390. static void channel_command (struct convection * cp);
  391. static void uptime_command (struct convection * cp);
  392. static int gatekeeper (struct convection * cp, int channel);
  393. static void accept_command (struct convection * cp);
  394. static void help_command (struct convection * cp);
  395. static void cstat_command (struct convection * cp);
  396. static void news_command (struct convection * cp);
  397. static void invite_command (struct convection * cp);
  398. static void links_command (struct convection * cp);
  399. static void msg_command (struct convection * cp);
  400. static void announce_new_user (struct convection * cp);
  401. static void color_command (struct convection * cp);
  402. static void set_personal (struct convection * cp);
  403. static void name_command (struct convection * cp);
  404.  
  405. #ifdef LZW
  406. static void compressed_command (struct convection * cp);
  407. #endif
  408.  
  409. static void sounds_command (struct convection * cp);
  410. static void update_user_data (struct convection * cp, int personal);
  411. static void password_command (struct convection * cp);
  412. static int isrosedigit (char c);
  413. static char *getVia (char *call);
  414. int CountConfUsers (void);
  415. static int CountConfGroups (void);
  416. #ifdef ALLSERV
  417. static void quote_command (struct convection * cp);
  418. #endif
  419. static void who_command (struct convection * cp);
  420. static void whois_command (struct convection * cp);
  421. static void realname_command (struct convection * cp);
  422. static void h_ecmd_command (struct convection * cp);
  423. static void h_cmsg_command (struct convection * cp);
  424. static void h_unknown_command (struct convection * cp);
  425. static void h_dest_command (struct convection * cp);
  426. static void h_topi_command (struct convection * cp);
  427. static void h_rout_command (struct convection * cp);
  428. static void h_ping_command (struct convection * cp);
  429. static void h_pong_command (struct convection * cp);
  430. static void h_link_command (struct convection * cp);
  431. static int Allow_host (int s);
  432. static void h_host_command (struct convection * cp);
  433. static void h_invi_command (struct convection * cp);
  434. static void h_loop_command (struct convection * cp);
  435. static void h_uadd_command (struct convection * cp);
  436. static void initialusers (int channel);
  437. static void h_ndat_command (struct convection * cp);
  438. static void h_ques_command (struct convection * cp);
  439. static void h_umsg_command (struct convection * cp);
  440. static void h_bump_command (struct convection * cp);
  441. static void h_user_command (struct convection * cp);
  442. static void gname_command (struct convection * cp, char *cptr);
  443. static void assignnet_command (struct convection * cp);
  444. static void bumpnet_command (struct convection * cp);
  445. static void process_question (int channel, char type, char *name, const char *cptr);
  446. static void question_command (struct convection * cp, char *cptr);
  447. static void log_command (struct convection * cp, char *cptr);
  448. static void nonet_command (struct convection * cp);
  449. static void gpassword_command (struct convection * cp, char *cptr, int disableit);
  450. static void gprivate_command (struct convection * cp, char *cptr);
  451. static void group_command (struct convection * cp);
  452. static void smiley_command (struct convection * cp);
  453.  
  454. #ifdef SAMCALLB
  455. static void call_command (struct convection * cp);
  456. #endif
  457.  
  458. static void glog_command (struct convection * cp);
  459. static void net_command (struct convection * cp);
  460. static void list_groups_command (struct convection * cp);
  461. static void join_command (struct convection * cp);
  462. static void process_commands (struct convection * cp, struct mbx * m);
  463. void conversWriteall (char *str);
  464. void conversWrite (char *str, char *user);
  465. int sockblock (int s, int value);
  466.  
  467. #if 0
  468. static void conv_usflush (int s);
  469. #endif
  470.  
  471. static char *ts3 (time_t seconds, char *buffer);
  472. static char *ts4 (time_t seconds);
  473. static int ecmd_exists (char *cmdname);
  474. static void getTXname (struct convection * cp, char *buf);
  475. static int ShowConfLinks2 (int s, char *user, int full);
  476.  
  477.  
  478. #undef CNAMELEN
  479. #define CNAMELEN 16
  480. char Chostname[CNAMELEN + 1], CConsole[CNAMELEN + 1];
  481. static char *mysysinfo;
  482.  
  483.  
  484. static char *confMOTD = NULLCHAR;
  485.  
  486. #define TOPICLEN 63
  487.  
  488. struct group {
  489.     int channel;        /* channel # for this group info */
  490.     char name[TOPICLEN + 1];/* group's name */
  491.     char password[NAMELEN + 1];    /* password required to enter group */
  492.     char moderator[NAMELEN + 1];    /* real name of current moderator */
  493.     FILE *qfile;        /* stream of current question file */
  494.     short nextq;        /* last question number in qfile */
  495.     short totalq;        /* total questions in qfile */
  496.     FILE *logfile;        /* stream of current logfile */
  497.     char logged;        /* status of log file (1=open) */
  498.     char private;        /* is it private (1 = yes) */
  499.     struct group *next;    /* next group in queue */
  500. };
  501.  
  502. #define NULLGROUP ((struct group *) 0)
  503. #define NOCONTROL ((struct group *) -1)
  504.  
  505.  
  506.  
  507. struct extendedcmds {
  508.     char *name;
  509.     struct extendedcmds *next;
  510. };
  511.  
  512. #define NULLEXTCMD ((struct extendedcmds *)0)
  513. static struct extendedcmds *ecmds;
  514.  
  515.  
  516. static char nonetoverride;
  517. static struct group *groups;
  518. static struct group *find_group (int channel);
  519. static void bye_command (struct convection * cp);
  520. static void update_net_data (struct group * gp);
  521. static struct group *get_group (struct convection * cp);
  522. static struct group *can_gcontrol (struct convection * cp);
  523. static struct group *lookup_group (char *name);
  524.  
  525. extern char *confMOTD;
  526. extern char Ccall[AXALEN], Calias[AXALEN];
  527. extern time_t StartTime;
  528.  
  529. static void setparamptr (struct convection *cp, char *str);
  530. static char *getparam (struct convection *cp);
  531. static char *getparamline (struct convection *cp);
  532.  
  533.  
  534. static int docfilter (int argc, char *argv[], void *p);
  535. static int doconvconsole (int argc, char *argv[], void *p);
  536. static int dochostname (int argc, char *argv[], void *p);
  537. static int doconvstat (int argc, char *argv[], void *p);
  538. static int doconvcstat (int argc, char *argv[], void *p);
  539. static int dociface (int argc, char *argv[], void *p);
  540. static int doconfcall (int argc, char *argv[], void *p);
  541. static int doconfalias (int argc, char *argv[], void *p);
  542. static int doclink (int argc, char *argv[], void *p);
  543. static int docunlink (int argc, char *argv[], void *p);
  544. static int dodrop (int argc, char *argv[], void *p);
  545. static int doct4 (int argc, char *argv[], void *p);
  546. static int doentrychannel (int argc, char *argv[], void *p);
  547. static int doconfmotd (int argc, char *argv[], void *p);
  548. static int dosysinfo (int argc, char *argv[], void *p);
  549. static int doconvnet0 (int argc, char *argv[], void *p);
  550. static int dotimestamp (int argc, char *argv[], void *p);
  551. static int docmaxwait (int argc, char *argv[], void *p);
  552. static int dohmaxq (int argc, char *argv[], void *p);
  553. static int doumaxq (int argc, char *argv[], void *p);
  554. static int doheader (int argc, char *argv[], void *p);
  555.  
  556. static struct cmds Ccmds[] =
  557. {
  558. #ifdef AX25
  559.     { "alias",        doconfalias,    0, 0, NULLCHAR },
  560. #endif
  561.     { "console",        doconvconsole,    0, 0, NULLCHAR },
  562.     { "cstat",        doconvcstat,    0, 0, NULLCHAR },
  563.     { "drop",        dodrop,        0, 0, NULLCHAR },
  564.     { "entrychannel",    doentrychannel,    0, 0, NULLCHAR },
  565.     { "filter",        docfilter,    0, 0, NULLCHAR },
  566.     { "hmaxq",        dohmaxq,    0, 0, NULLCHAR },
  567.     { "header",        doheader,    0, 0, NULLCHAR },
  568.     { "hostname",        dochostname,    0, 0, NULLCHAR },
  569.     { "interface",        dociface,    0, 0, NULLCHAR },
  570. #ifdef LINK
  571.     { "link",        doclink,    0, 0, NULLCHAR },
  572. #endif
  573.     { "maxwait",        docmaxwait,    0, 0, NULLCHAR },
  574. #ifdef AX25
  575.     { "motd",        doconfmotd,    0, 0, NULLCHAR },
  576.     { "mycall",        doconfcall,    0, 0, NULLCHAR },
  577. #endif
  578.     { "net0",        doconvnet0,    0, 0, NULLCHAR },
  579.     { "online",        doconvstat,    0, 0, NULLCHAR },
  580.     { "sysinfo",        dosysinfo,    0, 0, NULLCHAR },
  581. #ifdef AX25
  582.     { "t4",            doct4,        0, 0, NULLCHAR },
  583.     { "timestamp",        dotimestamp,    0, 0, NULLCHAR },
  584. #endif
  585.     { "umaxq",        doumaxq,    0, 0, NULLCHAR },
  586. #ifdef LINK
  587.     { "unlink",        docunlink,    0, 0, NULLCHAR },
  588. #endif
  589.     { NULLCHAR,        0,        0, 0, NULLCHAR }
  590. };
  591.  
  592.  
  593.  
  594. /* Multiplexer for top-level convers command */
  595. int
  596. doconvers (int argc, char *argv[], void *p)
  597. {
  598.     return subcmd (Ccmds, argc, argv, p);
  599. }
  600.  
  601.  
  602.  
  603. void setparamptr (struct convection *cp, char *str)
  604. {
  605.     cp->ibufpt = str;
  606. }
  607.  
  608.  
  609. /*---------------------------------------------------------------------------*/
  610.  
  611. char *
  612. getparamline (struct convection *cp)
  613. {
  614.     cp->ibufpt = skipwhite (cp->ibufpt);
  615.     return cp->ibufpt;
  616. }
  617.  
  618.  
  619. /*---------------------------------------------------------------------------*/
  620.  
  621. char *getparam (struct convection *cp)
  622. {
  623. char *arg;
  624.  
  625.     cp->ibufpt = skipwhite (cp->ibufpt);
  626.     arg = cp->ibufpt;
  627.     cp->ibufpt = skipnonwhite (cp->ibufpt);
  628.     if (*(cp->ibufpt))
  629.         *(cp->ibufpt)++ = '\0';
  630.     return arg;
  631. }
  632.  
  633.  
  634.  
  635. #ifdef AX25
  636. /* Display or change our AX.25 conference call */
  637. static int
  638. doconfcall (int argc, char *argv[], void *p OPTIONAL)
  639. {
  640. char tmp[AXBUF];
  641.  
  642.     if (argc < 2) {
  643.         tprintf (fullstrcr, pax25 (tmp, Ccall));
  644.         return 0;
  645.     }
  646.     if (setcall (Ccall, argv[1]) == -1)
  647.         return -1;
  648.     return 0;
  649. }
  650.  
  651.  
  652.  
  653. /* Display or change our AX.25 conference alias */
  654. static int
  655. doconfalias (int argc, char *argv[], void *p OPTIONAL)
  656. {
  657. char tmp[AXBUF];
  658.  
  659.     if (argc < 2) {
  660.         tprintf (fullstrcr, pax25 (tmp, Calias));
  661.         return 0;
  662.     }
  663.     if (setcall (Calias, argv[1]) == -1)
  664.         return -1;
  665.     return 0;
  666. }
  667.  
  668.  
  669.  
  670. /* Set link redundancy timer */
  671. static int
  672. doct4 (int argc, char *argv[], void *p OPTIONAL)
  673. {
  674.     return setlong (&CT4init, redun, argc, argv);
  675. }
  676.  
  677. #endif /* AX25 */
  678.  
  679.  
  680.  
  681. /* Set entry channel number */
  682. static int
  683. doentrychannel (int argc, char *argv[], void *p OPTIONAL)
  684. {
  685.     return setint (&CChannel, entrystr, argc, argv);
  686. }
  687.  
  688.  
  689.  
  690. /* Allow nets to be held on channel 0 */
  691. static int
  692. doconvnet0 (int argc, char *argv[], void *p OPTIONAL)
  693. {
  694.     return setbool (&ConvNet0, allownets, argc, argv);
  695. }
  696.  
  697.  
  698.  
  699. static int
  700. doconvstat (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  701. {
  702.     if (Current == Command)
  703.         Command->flowmode = 0;    /* clear 'more' paging on command screen */
  704.     (void) ShowConfUsers (Curproc->output, NULLCHAR);
  705.     tputs ("\n");
  706.     if (Current == Command)
  707.         Command->flowmode = 1;    /* set 'more' paging on command screen */
  708.     return 0;
  709. }
  710.  
  711.  
  712.  
  713. static int
  714. doconvcstat (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  715. {
  716.     (void) ShowConfLinks (Curproc->output, 1);
  717.     tputs ("\n");
  718.     (void) ShowConfDest (Curproc->output, "", "");
  719.     tputs ("\n");
  720.     return 0;
  721. }
  722.  
  723.  
  724.  
  725. /* Give login header */
  726. static int
  727. doheader (int argc, char *argv[], void *p OPTIONAL)
  728. {
  729.     return setbool (&ConvHeader, givehead, argc, argv);
  730. }
  731.  
  732.  
  733.  
  734. /* Allow broadcasts to be timestamped */
  735. static int
  736. dotimestamp (int argc, char *argv[], void *p OPTIONAL)
  737. {
  738.     return setbool (&TimeStamp, timestampstr, argc, argv);
  739. }
  740.  
  741.  
  742.  
  743. static int
  744. dociface (int argc, char *argv[], void *p)
  745. {
  746.     return (dosetflag (argc, argv, p, IS_CONV_IFACE, 1));
  747. }
  748.  
  749.  
  750.  
  751. /* Set maxwait time for timed out links */
  752. static int
  753. docmaxwait (int argc, char *argv[], void *p OPTIONAL)
  754. {
  755.     return setlong (&CMaxwait, maxwaitstr, argc, argv);
  756. }
  757.  
  758.  
  759.  
  760. /* Set max qlimit for host links */
  761. static int
  762. dohmaxq (int argc, char *argv[], void *p OPTIONAL)
  763. {
  764.     return setint (&HMaxQ, hostqueuestr, argc, argv);
  765. }
  766.  
  767.  
  768.  
  769. /* Set max qlimit for user links */
  770. static int
  771. doumaxq (int argc, char *argv[], void *p OPTIONAL)
  772. {
  773.     return setint (&UMaxQ, userqueuestr, argc, argv);
  774. }
  775.  
  776.  
  777.  
  778. static int
  779. dochostname (int argc, char *argv[], void *p OPTIONAL)
  780. {
  781.     if (argc == 1)
  782.         tprintf (fullstrcr, Chostname);
  783.     else {
  784.         strncpy (Chostname, argv[1], NAMELEN);
  785.         Chostname[NAMELEN] = '\0';
  786.     }
  787.     return 0;
  788. }
  789.  
  790.  
  791.  
  792. static int
  793. doconvconsole (int argc, char *argv[], void *p OPTIONAL)
  794. {
  795.     if (argc == 1)
  796.         tprintf (fullstrcr, CConsole);
  797.     else {
  798.         strncpy (CConsole, argv[1], NAMELEN);
  799.         CConsole[NAMELEN] = '\0';
  800.     }
  801.     return 0;
  802. }
  803.  
  804.  
  805.  
  806. /* View/Change the message we send to new conference connects. */
  807.  
  808. static int 
  809. doconfmotd (int argc, char *argv[], void *p OPTIONAL)
  810. {
  811.     if (argc < 2)
  812.         tprintf (motdstr, confMOTD);
  813.     else {
  814.         if (confMOTD != NULL)
  815.             free (confMOTD);
  816.         confMOTD = strdup (argv[1]);
  817.     }
  818.     return 0;
  819. }
  820.  
  821.  
  822.  
  823. /* View/Change the message we send in response to sysinfo requests. */
  824.  
  825. static int 
  826. dosysinfo (int argc, char *argv[], void *p OPTIONAL)
  827. {
  828.     if (argc < 2)
  829.         tprintf (sysinfostr, mysysinfo);
  830.     else {
  831.         if (mysysinfo != NULL)
  832.             free (mysysinfo);
  833.         mysysinfo = strdup (argv[1]);
  834.     }
  835.     return 0;
  836. }
  837.  
  838.  
  839.  
  840. static int
  841. docfilter (int argc, char *argv[], void *p OPTIONAL)
  842. {
  843. uint32 addr;
  844. struct filter_link *fl;
  845.  
  846.     if (argc == 1) {
  847.         if (Filterlinks) {
  848.             tprintf (modeis, FilterMode ? acceptstr : refuse);
  849.             for (fl = Filterlinks; fl; fl = fl->next)
  850.                 tprintf (fullstrcr, inet_ntoa (fl->addr));
  851.         }
  852.         return 0;
  853.     }
  854.     if (!stricmp (argv[1], "mode")) {
  855.         if (argc == 2)
  856.             tprintf (modeis, FilterMode ? acceptstr : refuse);
  857.         else {
  858.             if (*argv[2] == 'a' || *argv[2] == 'A')
  859.                 FilterMode = 1;
  860.             else
  861.                 FilterMode = 0;
  862.         }
  863.         return 0;
  864.     }
  865.     if ((addr = resolve (argv[1])) == 0) {
  866.         tprintf (Badhost, argv[1]);
  867.         return 1;
  868.     }
  869.     /* check to see if we already have this in the list */
  870.     for (fl = Filterlinks; fl; fl = fl->next)
  871.         if (fl->addr == addr)
  872.             return 0;    /* already have this one ! */
  873.  
  874.     /* Seems like a new one */
  875.     fl = (struct filter_link *) callocw (1, sizeof (struct filter_link));
  876.  
  877.     fl->addr = addr;
  878.     fl->next = Filterlinks;
  879.     Filterlinks = fl;
  880.     return 0;
  881. }
  882.  
  883.  
  884.  
  885. #ifdef LINK
  886. static int
  887. doclink (int argc, char *argv[], void *p OPTIONAL)
  888. {
  889. uint32 addr;
  890. struct permlink *pl;
  891.  
  892.     if (argc == 1) {
  893.         for (pl = permlinks; pl; pl = pl->next)
  894.             tprintf (fullstrcr, inet_ntoa (pl->addr));
  895.         return 0;
  896.     }
  897.     if ((addr = resolve (argv[1])) == 0) {
  898.         tprintf (Badhost, argv[1]);
  899.         return 1;
  900.     }
  901.     /* check to see if we already have a link to such animal,
  902.      * this happens when we stop and restart the server - WG7J
  903.      */
  904.     for (pl = permlinks; pl; pl = pl->next)
  905.         if (pl->addr == addr)
  906.             return 1;    /* already have this one ! */
  907.  
  908.     /* Seems like a new link ! Go add it */
  909.     pl = (struct permlink *) callocw (1, sizeof (struct permlink));
  910.  
  911.     pl->addr = addr;
  912.     pl->next = permlinks;
  913.     permlinks = pl;
  914.     pl->port = (int16) ((argc > 2) ? atoi (argv[2]) : IPPORT_CONVERS);
  915.     if (argc > 3)
  916.         strncpy (pl->name, argv[3], NAMELEN);
  917.     else
  918.         strncpy (pl->name, argv[1], NAMELEN);
  919.  
  920.     update_permlinks (pl->name, NULLCONNECTION);
  921.     pl->retrytime -= 55;    /* 1st start in 5 seconds */
  922.     pl->waittime = 30;    /* 2nd after 1 minute */
  923.  
  924.     if (!Linker)
  925.         Linker = newproc ("Converse linker", 1024, connect_permlinks, 0, 0, NULL, 0);
  926.  
  927.     return 0;
  928. }
  929.  
  930.  
  931.  
  932. static int
  933. docunlink (int argc, char *argv[], void *p OPTIONAL)
  934. {
  935. uint32 addr;
  936. struct permlink *pl, *pls;
  937.  
  938.     if (argc == 1) {
  939.         pl = permlinks;
  940.         permlinks = NULLPERMLINK;
  941.         while (pl) {
  942.             tprintf ("Unlinking %s\n", inet_ntoa (pl->addr));
  943.             (void) shutdown (pl->fd, 2);
  944.             close_s (pl->fd);
  945.             pls = pl->next;
  946.             free (pl);
  947.             pl = pls;
  948.         }
  949.         return 0;
  950.     }
  951. #if 0
  952.     if ((addr = resolve (argv[1])) == 0) {
  953.         tprintf (Badhost, argv[1]);
  954.         return 1;
  955.     }
  956. #else
  957.     addr = resolve (argv[1]);
  958. #endif
  959.  
  960.     pls = NULLPERMLINK;
  961.     for (pl = permlinks; pl; pls = pl, pl = pl->next)
  962.         if ((pl->addr == addr) || !stricmp (pl->name, argv[1])) {
  963.             if (pls)
  964.                 pls->next = pl->next;
  965.             else
  966.                 permlinks = pl->next;
  967.             tprintf ("Unlinking %s: %s\n", inet_ntoa (pl->addr), pl->name);
  968.             (void) shutdown (pl->fd, 2);
  969.             close_s (pl->fd);
  970.             free (pl);
  971.             return 0;
  972.         }
  973.     tprintf ("Not linked to %s\n", argv[1]);
  974.     return 0;
  975. }
  976. #endif
  977.  
  978.  
  979.  
  980. static int
  981. dodrop (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
  982. {
  983. struct convection *pl, *pls;
  984.  
  985.     pls = NULLCONNECTION;
  986.     for (pl = convections; pl; pls = pl, pl = pl->next)
  987.         if (!stricmp (pl->name, argv[1])) {
  988.             if (pls)
  989.                 pls->next = pl->next;
  990.             else
  991.                 convections = pl->next;
  992.             tprintf ("Droping %s\n", pl->name);
  993.             (void) shutdown (pl->fd, 2);
  994.             close_s (pl->fd);
  995.             free (pl);
  996.             return 0;
  997.         }
  998.     tprintf ("Cannot drop %s: not connected\n", argv[1]);
  999.     return 0;
  1000. }
  1001.  
  1002.  
  1003.  
  1004. /* Stop convers server */
  1005. int
  1006. conv0 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  1007. {
  1008. #ifdef LINK
  1009.     if (Linker) {
  1010.         killproc (Linker);
  1011.         Linker = 0;
  1012.     }
  1013. #endif
  1014.     return (deleteserver (&Sconv));
  1015. }
  1016.  
  1017.  
  1018.  
  1019. /* Start up convers server */
  1020. int
  1021. conv1 (int argc, char *argv[], void *p OPTIONAL)
  1022. {
  1023. int port;
  1024.  
  1025.     Conv_mutex = TNOS_MUTEX_UNLOCKED;
  1026.     Group_mutex = TNOS_MUTEX_UNLOCKED;
  1027.     if (!Chostname[0])    {
  1028.         if (Hostname)
  1029.             strncpy (Chostname, Hostname, CNAMELEN);
  1030.         else
  1031.             strcpy (Chostname, "localhost");
  1032.     }
  1033.     port = (argc > 1) ? atoi (argv[1]) : IPPORT_CONVERS;
  1034.     (void) installserver (argc, argv, &Sconv, "Conference listener", port,
  1035.         INADDR_ANY, conversd, conv_incom, 1024, NULL);
  1036. #ifdef LINK
  1037.     if (Linker) {
  1038.         killproc (Linker);
  1039.         Linker = 0;
  1040.     }
  1041. #endif
  1042.     return 0;
  1043. }
  1044.  
  1045.  
  1046.  
  1047. static void
  1048. free_connection (register struct convection *cp)
  1049. {
  1050. register struct permlink *p;
  1051.  
  1052.     for (p = permlinks; p; p = p->next)
  1053.         if (p->convection == cp)
  1054.             p->convection = NULLCONNECTION;
  1055.     free (cp->ibuf);
  1056.     if (cp->flags & CLOSE_SOCK)
  1057.         close_s (cp->fd);
  1058.     free ((char *) cp);
  1059. }
  1060.  
  1061.  
  1062.  
  1063. static void
  1064. free_closed_connections (void)
  1065. {
  1066. register struct convection *cp, *p;
  1067. time_t currtime;
  1068.  
  1069.     currtime = time (&currtime);
  1070.  
  1071.     for (p = NULLCONNECTION, cp = convections; cp;)
  1072.         if (cp->type == CT_CLOSED || (cp->type == CT_UNKNOWN && cp->time + 300 < currtime)) {
  1073.             if (p) {
  1074.                 p->next = cp->next;
  1075.                 free_connection (cp);
  1076.                 cp = p->next;
  1077.             } else {
  1078.                 convections = cp->next;
  1079.                 free_connection (cp);
  1080.                 cp = convections;
  1081.             }
  1082.         } else {
  1083.             p = cp;
  1084.             cp = cp->next;
  1085.         }
  1086. }
  1087.  
  1088.  
  1089.  
  1090. static void
  1091. update_permlinks (char *name, struct convection *cp)
  1092. {
  1093. register struct permlink *p;
  1094. time_t currtime;
  1095. struct destination *d;
  1096.  
  1097.     for (p = permlinks; p; p = p->next) {
  1098.         if (!strcmp (p->name, name)) {
  1099.             for (d = destinations; d; d = d->next) {
  1100.                 if (d->rtt && (d->link == p))
  1101.                     update_destinations (p, d->name, 0, "");
  1102.             }
  1103.             currtime = time (&currtime);
  1104.             p->convection = cp;
  1105.             p->statetime = currtime;
  1106.             p->tries = 0;
  1107.             p->waittime = 60;
  1108.             p->rxtime = 0;
  1109.             p->txtime = 0;
  1110.             p->testwaittime = currtime;
  1111.             p->testnexttime = currtime + 60;
  1112.             p->retrytime = currtime + p->waittime;
  1113.         }
  1114.     }
  1115. }
  1116.  
  1117.  
  1118.  
  1119. static struct convection *
  1120. alloc_connection (int fd)
  1121. {
  1122. register struct convection *cp;
  1123. time_t currtime;
  1124.  
  1125.     currtime = time (NULL);
  1126.  
  1127.     cp = (struct convection *) callocw (1, sizeof (struct convection));
  1128.  
  1129.     cp->ibuf = (char *) callocw (1, INBUFLEN + 1);
  1130.     cp->fd = fd;
  1131.     cp->maxq = UMaxQ;    /* Maximum qlimit for user */
  1132.     cp->flags = CLOSE_SOCK + USE_SOUND;    /* close on exit, by default */
  1133.     cp->time = currtime;
  1134.     cp->paged = -1;
  1135.     cp->net = -1;
  1136.     cp->features = 0;
  1137.     kmutex_lock (&Conv_mutex);
  1138.     cp->next = convections;
  1139.     convections = cp;
  1140.     kmutex_unlock (&Conv_mutex);
  1141.     return cp;
  1142. }
  1143.  
  1144.  
  1145.  
  1146. #ifdef LINK
  1147. /* check the host links for backlogged data.
  1148.  * If larger then set threshold, kill the link.
  1149.  * WG7J, 930208
  1150.  */
  1151. static void 
  1152. check_buffer_overload (void)
  1153. {
  1154. struct convection *p;
  1155.  
  1156.     /* check the size of the outstanding data buffers */
  1157.     for (p = convections; p; p = p->next)
  1158.         if ((p->maxq != 0) && (socklen (p->fd, 1) > p->maxq)) {
  1159.             /* Blow this one out of the water */
  1160.             (void) shutdown (p->fd, 2);
  1161.             close_s (p->fd);
  1162.         }
  1163. }
  1164.  
  1165.  
  1166.  
  1167. void
  1168. connect_permlinks (int a OPTIONAL, void *b OPTIONAL, void *c OPTIONAL)
  1169. {
  1170. int s;
  1171. register struct permlink *p;
  1172. struct sockaddr_in cport;
  1173. time_t currtime;
  1174. struct destination *d;
  1175. char buffer[256];
  1176.  
  1177.     server_disconnect_io ();
  1178.     for ( ; ; ) {
  1179.         kpause (15000L);
  1180.         currtime = time (&currtime);
  1181.         for (p = permlinks; p; p = p->next) {
  1182.             /* Update our existing connections */
  1183.             if (p->convection) {
  1184.                 if (p->testnexttime < currtime) {
  1185.                     if ((p->testwaittime + 7300) < currtime) {
  1186.                         p->rxtime = 0;
  1187.                         p->txtime = 0;
  1188.                         for (d = destinations; d; d = d->next) {
  1189.                             if (d->link == p)
  1190.                                 update_destinations (p, d->name, 0, "");
  1191.                         }
  1192.                     }
  1193.                     p->convection->xmitted += usprintf (p->convection->fd, "/\377\200PING\n");
  1194.                     p->testwaittime = currtime;
  1195.                     p->testnexttime = currtime + 7300;
  1196.                 }
  1197.             }
  1198.         }
  1199.  
  1200.         for (p = permlinks; p; p = p->next) {
  1201.             if (p->convection || p->retrytime > currtime)
  1202.                 continue;
  1203.             p->tries++;
  1204.             p->waittime <<= 1;    /*lint !e703 */
  1205.             if (p->waittime > (time_t) CMaxwait)
  1206.                 p->waittime = (time_t) CMaxwait;
  1207.             p->retrytime = p->waittime + currtime;
  1208.             cport.sin_family = AF_INET;
  1209.             cport.sin_port = p->port;
  1210.             cport.sin_addr.s_addr = p->addr;    /* we've resolved this earlier */
  1211.             if ((s = socket (AF_INET, SOCK_STREAM, 0)) == -1)
  1212.                 continue;
  1213.             if (connect (s, (char *) &cport, SOCKSIZE) == -1) {
  1214.                 (void) shutdown (s, 2);    /* to make sure it doesn't linger around */
  1215.                 close_s (s);    /* WG7J - 9207228 */
  1216.                 continue;
  1217.             }
  1218.             p->fd = s;
  1219.             sprintf (buffer, "permlink: %s", inet_ntoa (p->addr));
  1220.             if (newproc (buffer, 2048, conv_incom, s, 0, NULL, 0) == NULLPROC) {
  1221.                 (void) shutdown (s, 2);    /* blow it out of the water :-) */
  1222.                 close_s (s);
  1223.             }
  1224.         }
  1225.         check_buffer_overload ();
  1226.     }
  1227. }
  1228. #endif
  1229.  
  1230.  
  1231.  
  1232. static int
  1233. ecmd_exists (char *cmdname)
  1234. {
  1235. struct extendedcmds *echk;
  1236.  
  1237.     echk = ecmds;
  1238.     while (echk && echk->name) {
  1239.         if (!stricmp (echk->name, cmdname))
  1240.             return 1;
  1241.         echk = echk->next;
  1242.     }
  1243.     return 0;
  1244. }
  1245.  
  1246.  
  1247.  
  1248. static void
  1249. clear_locks (void)
  1250. {
  1251. register struct convection *p;
  1252.  
  1253.     for (p = convections; p; p = p->next)
  1254.         p->locked = 0;
  1255. }
  1256.  
  1257.  
  1258.  
  1259. static void 
  1260. send_sounds (struct convection *p)
  1261. {
  1262.     if (p->flags & USE_SOUND)
  1263.         p->xmitted += usputs (p->fd, "");
  1264. }
  1265.  
  1266.  
  1267.  
  1268. static char *
  1269. timestring (time_t gmt)
  1270. {
  1271. static char buffer[10];
  1272. struct tm *tm;
  1273. time_t currtime;
  1274.  
  1275.     currtime = time (&currtime);
  1276.  
  1277.  
  1278.     tm = localtime (&gmt);
  1279.     if (gmt + 24 * 60 * 60 > currtime)
  1280.         sprintf (buffer, " %02d:%02d", tm->tm_hour, tm->tm_min);
  1281.     else
  1282.         sprintf (buffer, "%-3.3s %2d", Months[tm->tm_mon], tm->tm_mday);
  1283.     return buffer;
  1284. }
  1285.  
  1286.  
  1287.  
  1288. static void
  1289. send_user_change_msg (
  1290. char *name,
  1291. char *host,
  1292. time_t mytime,
  1293. int oldchannel,
  1294. int newchannel,
  1295. char *pers
  1296. ) {
  1297. register struct convection *p;
  1298. time_t currtime;
  1299. register struct group *gold, *gnew;
  1300.  
  1301.     currtime = time (&currtime);
  1302.  
  1303.     gold = find_group (oldchannel);
  1304.     gnew = find_group (newchannel);
  1305.     if (gold && gold->logfile) {
  1306.         if (newchannel >= 0)
  1307.             fprintf (gold->logfile, theyswitched, stars,
  1308.                  name, newchannel, timestring (currtime));
  1309.         else
  1310.             fprintf (gold->logfile, theysigned, stars, name, ff_str, timestring (currtime));
  1311.     }
  1312.     if (gnew && gnew->logfile)
  1313.         fprintf (gnew->logfile, theysigned, stars, name, n_str, timestring (currtime));
  1314.  
  1315.     for (p = convections; p; p = p->next) {
  1316.         kwait (NULL);
  1317.         if (p->type == CT_USER && !p->via && !p->locked) {
  1318.             if ((newchannel == oldchannel) && (newchannel != -1)) {
  1319.                 if (p->channel == newchannel) {
  1320.                     if (pers && (*pers != '\0') && (strcmp (pers, "@")))
  1321.                         p->xmitted += usprintf (p->fd, "*** (%s) %s@%s on channel %d set personal text:\n    %s\n", timestring (currtime), name, host, newchannel, pers);
  1322.                     else
  1323.                         p->xmitted += usprintf (p->fd, "*** (%s) %s@%s on channel %d removed personal text.\n", timestring (currtime), name, host, newchannel);
  1324.                     p->locked = 1;
  1325.                 }
  1326.             } else {
  1327.                 if (p->channel == oldchannel) {
  1328.                     convcolorchange (p, SYSCOLORS);
  1329.                     if (newchannel >= 0)
  1330.                         p->xmitted += usprintf (p->fd, theyswitched, stars,
  1331.                             name, newchannel, timestring (currtime));
  1332.                     else
  1333.                         p->xmitted += usprintf (p->fd,
  1334.                             theysigned, stars, name, ff_str, timestring (currtime));
  1335.                     p->locked = 1;
  1336.                 }
  1337.                 if (p->channel == newchannel) {
  1338.                     convcolorchange (p, SYSCOLORS);
  1339.                     send_sounds (p);
  1340.                     p->xmitted += usprintf (p->fd,
  1341.                         theysigned, stars, name, n_str, timestring (currtime));
  1342.                     p->locked = 1;
  1343.                 }
  1344.             }
  1345.         }
  1346.         if (p->type == CT_HOST && !p->locked) {
  1347.             p->xmitted += usprintf (p->fd, huserstr, name, host, mytime, oldchannel, newchannel, (pers) ? pers : "");
  1348.             p->locked = 1;
  1349.         }
  1350.     }
  1351. #ifdef XSERVER
  1352.     xnotify (X_CONF);
  1353. #endif
  1354. }
  1355.  
  1356.  
  1357.  
  1358. static char *
  1359. formatline (char *prefix, const char *text)
  1360. {
  1361. register const char *f, *x;
  1362. register char *t;
  1363. register int l, lw;
  1364. static char buf[2 * LINELEN];
  1365.  
  1366.     for (f = prefix, t = buf; *f; *t++ = *f++)
  1367.         ;
  1368.     l = (int) (t - buf);
  1369.     f = text;
  1370.     *t++ = ' ';
  1371.     l++;
  1372.  
  1373.     for ( ; ; ) {
  1374.         while (isspace (uchar (*f))) {
  1375. #ifndef NOSPACES
  1376.             *t++ = *f;
  1377.             l++;
  1378. #endif
  1379.             f++;
  1380.         }
  1381.         if (!*f) {
  1382.             *t++ = '\n';
  1383.             *t = '\0';
  1384.             return buf;
  1385.         }
  1386.         for (x = f; *x && !isspace (uchar (*x)); x++)
  1387.             ;
  1388.         lw = (int) (x - f);
  1389.         if (l > PREFIXLEN && l + 1 + lw > CONVLINELEN) {
  1390.             *t++ = '\n';
  1391.             l = 0;
  1392.         }
  1393. #ifndef NOSPACES
  1394.         while (l < PREFIXLEN) {
  1395. #else
  1396.         do {
  1397. #endif
  1398.             *t++ = ' ';
  1399.             l++;
  1400. #ifndef NOSPACES
  1401.         }
  1402. #else
  1403.         } while (l < PREFIXLEN);
  1404. #endif
  1405.         while (lw--) {
  1406.             *t++ = *f++;
  1407.             l++;
  1408.         }
  1409.     }
  1410. }
  1411.  
  1412.  
  1413.  
  1414. static void
  1415. send_msg_to_user (const char *fromname, const char *toname, const char *text)
  1416. {
  1417. register struct convection *p;
  1418. char buff2[INBUFLEN];
  1419.  
  1420.     strncpy (buff2, text, INBUFLEN);
  1421.     rip (buff2);
  1422.     for (p = convections; p; p = p->next) {
  1423.         kwait (NULL);
  1424.         if (p->type == CT_USER && (!strcmpi (p->name, toname) || !strcmpi (p->nickname, toname)))
  1425.             if (p->via) {
  1426.                 if (!p->via->locked) {
  1427.                     p->via->xmitted += usprintf (p->via->fd,
  1428.                         umsgstr, fromname, toname, buff2);
  1429.                     p->via->locked = 1;
  1430.                 }
  1431.             } else {
  1432.                 if (!p->locked) {
  1433.                     if (strcmp (fromname, conversd)) {
  1434.                         char buffer[8 + (NAMELEN * 2)];
  1435.                         time_t currtime;
  1436.  
  1437.                         currtime = time (&currtime);
  1438.                         convcolorchange (p, INFOCOLORS);
  1439.                         sprintf (buffer, (TimeStamp) ? timestampfmt : nontimestampfmt, fromname, timestring (currtime));
  1440.                         p->xmitted += usprintf (p->fd, fullstr, formatline (buffer, buff2));
  1441.                     } else {
  1442.                         convcolorchange (p, SYSCOLORS);
  1443.                         p->xmitted += usprintf (p->fd, fullstrcr, buff2);
  1444.                     }
  1445.                     p->locked = 1;
  1446.                 }
  1447.             }
  1448.     }
  1449. }
  1450.  
  1451.  
  1452.  
  1453. static void
  1454. send_msg_to_channel (const char *fromname, int channel, const char *text)
  1455. {
  1456. char buffer[8 + (NAMELEN * 2)];
  1457. register struct convection *p;
  1458. register struct group *gp;
  1459. time_t currtime;
  1460. char buff2[INBUFLEN];
  1461.  
  1462.     strncpy (buff2, text, INBUFLEN);
  1463.     rip (buff2);
  1464.  
  1465.     currtime = time (&currtime);
  1466.     sprintf (buffer, (TimeStamp) ? timestampfmt2 : nontimestampfmt2, fromname, timestring (currtime));
  1467.     gp = find_group (channel);
  1468.     if (gp && gp->logfile)    {
  1469.         if (!strcmp (fromname, conversd))
  1470.             fprintf (gp->logfile, fullstrcr, buff2);
  1471.         else
  1472.             fprintf (gp->logfile, fullstr, formatline (buffer, buff2));
  1473.     }
  1474.  
  1475.     for (p = convections; p; p = p->next) {
  1476.         kwait (NULL);
  1477.         if (p->type == CT_USER && p->channel == channel)
  1478.             if (p->via) {
  1479.                 if (!p->via->locked) {
  1480.                     if ((p->via->features & FEATURE_NICK) || !strchr (fromname, ':'))
  1481.                         p->via->xmitted += usprintf (p->via->fd,
  1482.                             cmsgstr, fromname, channel, buff2);
  1483.                     else {
  1484.                         char *cp2;
  1485.                         char *ctmp = strdup (fromname);
  1486.  
  1487.                         cp2 = strchr (fromname, ':');
  1488.                         if (cp2)
  1489.                             *cp2 = 0;
  1490.                         p->via->xmitted += usprintf (p->via->fd,
  1491.                             cmsgstr, ctmp, channel, buff2);
  1492.                         free (ctmp);
  1493.                     }
  1494.                     p->via->locked = 1;
  1495.                 }
  1496.             } else {
  1497.                 if (!p->locked) {
  1498.                     convcolorchange (p, TEXTCOLORS);
  1499.                     if (!strcmp (fromname, conversd))
  1500.                         p->xmitted += usprintf (p->fd, fullstrcr, buff2);
  1501.                     else
  1502.                         p->xmitted += usprintf (p->fd, fullstr, formatline (buffer, buff2));
  1503.                     p->locked = 1;
  1504.                     usflush (p->fd);
  1505.                 }
  1506.             }
  1507.     }
  1508. }
  1509.  
  1510.  
  1511.  
  1512. static void
  1513. send_invite_msg (
  1514. char *fromname,
  1515. char *toname,
  1516. int channel,
  1517. char *msg
  1518. ) {
  1519. char buffer[80];
  1520. struct convection *p;
  1521. time_t currtime;
  1522. #ifdef MAILBOX
  1523. int i;
  1524. struct mbx *m = 0;
  1525. #endif
  1526.  
  1527.     currtime = time (&currtime);
  1528.  
  1529. #ifdef MAILBOX
  1530.     for (i = 0; i < NUMMBX; i++) {
  1531.         if ((m = Mbox[i]) != NULLMBX) {
  1532.             if (m->state == MBX_CMD && !stricmp (m->name, toname)) {
  1533.                 usprintf (m->user, mbinvitetext, amessage, fromname, timestring (currtime), stars, channel, channel);
  1534.                 if (msg[0])
  1535.                     usprintf (m->user, msgtext, fromname, msg);
  1536.                 usflush (m->user);
  1537.                 clear_locks ();
  1538.                 sprintf (buffer, responsetext, stars, toname, "BBS@");
  1539.                 strcat (buffer, Hostname);
  1540.                 send_msg_to_user (conversd, fromname, buffer);
  1541.                 return;
  1542.             }
  1543.         }
  1544.     }
  1545. #endif
  1546.  
  1547.     /* check the current convers users */
  1548.     for (p = convections; p; p = p->next) {
  1549.         if (p->type == CT_USER && !strcmpi (p->name, toname)) {
  1550.             if (p->channel == channel) {
  1551.                 clear_locks ();
  1552.                 sprintf (buffer, alreadyon, stars, userstr, toname);
  1553.                 send_msg_to_user (conversd, fromname, buffer);
  1554.                 return;
  1555.             }
  1556.             if (!p->via && !p->locked) {
  1557.                 convcolorchange (p, INFOCOLORS);
  1558.                 p->paged = channel;
  1559.                 p->xmitted += usprintf (p->fd, invitetext, amessage, fromname, \
  1560.                     timestring (currtime), stars, channel);
  1561.                 if (msg[0])
  1562.                     p->xmitted += usprintf (p->fd, msgtext, fromname, msg);
  1563.                 clear_locks ();
  1564.                 sprintf (buffer, responsetext, stars, toname, Chostname);
  1565.                 send_msg_to_user (conversd, fromname, buffer);
  1566.                 return;
  1567.             }
  1568.             if (p->via && !p->via->locked) {
  1569.                 p->via->xmitted += usprintf (p->via->fd, hinvi, fromname, toname, channel, msg);
  1570.                 return;
  1571.             }
  1572.         }
  1573.     }
  1574.     /* Nothing found locally, invite user on all links */
  1575.     for (p = convections; p; p = p->next) {
  1576.         if (p->type == CT_HOST && !p->locked)
  1577.             p->xmitted += usprintf (p->fd, hinvi, fromname, toname, channel, msg);
  1578.     }
  1579. }
  1580.  
  1581.  
  1582.  
  1583. static void
  1584. getTXname (struct convection *cp, char *buf)
  1585. {
  1586.     if (!stricmp (cp->nickname, cp->name))
  1587.         strcpy (buf, cp->name);
  1588.     else
  1589.         sprintf (buf, "%s:%s", cp->name, cp->nickname);
  1590. }
  1591.  
  1592.  
  1593.  
  1594. static void
  1595. cq_command (struct convection *cp)
  1596. {
  1597. register struct convection *p;
  1598. char *s, tmpbuff[2048];
  1599. char buf[(NAMELEN * 2) + 2];
  1600.  
  1601.     s = getparamline (cp);
  1602.     getTXname (cp, buf);
  1603.     sprintf (tmpbuff, "*** %s@%s channel %d calling CQ %s", buf, cp->host, cp->channel, s);
  1604.     for (p = convections; p; p = p->next) {
  1605.         if (p != cp)
  1606.             send_msg_to_user ("conversd", p->name, tmpbuff);
  1607.     }
  1608. }
  1609.  
  1610.  
  1611.  
  1612. static void
  1613. time_command (struct convection *cp)
  1614. {
  1615. time_t currtime;
  1616. char buff[24];
  1617.  
  1618.     currtime = time (&currtime);
  1619.     sprintf (buff, "%s%s is %s\n", stars, tmstr, timestring (currtime));
  1620.     clear_locks ();
  1621.     send_msg_to_channel (conversd, cp->channel, buff);
  1622. }
  1623.  
  1624.  
  1625.  
  1626. static void
  1627. version_command (struct convection *cp)
  1628. {
  1629.     cp->xmitted += usprintf (cp->fd, "%s%s Conference Bridge\n", stars, Version);
  1630. }
  1631.  
  1632.  
  1633.  
  1634. static int
  1635. onchannel (int channel)
  1636. {
  1637. int cnt = 0;
  1638. struct convection *p;
  1639.  
  1640.     for (p = convections; p; p = p->next)
  1641.         if (p->type == CT_USER && channel == p->channel)
  1642.             cnt++;
  1643.     return (cnt);
  1644. }
  1645.  
  1646.  
  1647.  
  1648. static void
  1649. bye_command (struct convection *cp)
  1650. {
  1651. register struct convection *p;
  1652. register struct permlink *pp;
  1653.  
  1654.     if (cp->net != -1) {
  1655.         int old = cp->channel;
  1656.  
  1657.         cp->channel = cp->net;
  1658.         nonet_command (cp);
  1659.         cp->channel = old;
  1660.     }
  1661.     switch (cp->type) {
  1662.         case CT_UNKNOWN:
  1663.             cp->type = CT_CLOSED;
  1664.             break;
  1665.         case CT_USER:
  1666.             cp->type = CT_CLOSED;
  1667.             convcolorchange (cp, SYSCOLORS);
  1668.             cp->xmitted += usprintf (cp->fd, exitingstr, conferencestr, Chostname);
  1669.             clear_locks ();
  1670.             send_user_change_msg (cp->name, cp->host, cp->time, cp->channel, -1, cp->data);
  1671.             save_personal (cp);
  1672.             break;
  1673.         case CT_HOST:
  1674.             cp->type = CT_CLOSED;
  1675.             for (pp = permlinks; pp; pp = pp->next)
  1676.                 if (pp->convection == cp) {
  1677.                     update_permlinks (pp->name, NULLCONNECTION);
  1678.                     break;
  1679.                 }
  1680.             for (p = convections; p; p = p->next)
  1681.                 if (p->via == cp) {
  1682.                     p->type = CT_CLOSED;
  1683.                     clear_locks ();
  1684.                     send_user_change_msg (p->name, p->host, p->time, p->channel, -1, p->data);
  1685.                 }
  1686.             break;
  1687.         case CT_CLOSED:
  1688.         default:
  1689.             break;
  1690.     }
  1691. }
  1692.  
  1693.  
  1694.  
  1695. static void
  1696. mystatus (struct convection *cp, int old)
  1697. {
  1698. int now;
  1699. struct group *gp;
  1700.  
  1701.     now = onchannel (cp->channel);
  1702.     cp->xmitted += usprintf (cp->fd, nowchannel, stars, channelstr, cp->channel, now, (now > 1) ? "s" : empty);
  1703.     gp = find_group (cp->channel);
  1704.     if (gp != NULLGROUP) {
  1705.         convcolorchange (cp, SYSCOLORS);
  1706.         cp->xmitted += usprintf (cp->fd, welcome, stars, (gp->private) ? privatestr : empty,
  1707.                      (gp->private) ? " " : empty, gp->name);
  1708.         if (*gp->moderator)
  1709.             cp->xmitted += usprintf (cp->fd, welcome2, netcontrolstr, gp->moderator);
  1710.         cp->xmitted += usprintf (cp->fd, welcome3, cp->nickname);
  1711.     }
  1712.     send_user_change_msg (cp->name, cp->host, cp->time, old, cp->channel, cp->data);
  1713. }
  1714.  
  1715.  
  1716.  
  1717. static void
  1718. channel_command (struct convection *cp)
  1719. {
  1720. char *s;
  1721. int newchannel, oldchannel;
  1722.  
  1723.     s = getparam (cp);
  1724.     if (*s == '\0') {
  1725.         convcolorchange (cp, SYSCOLORS);
  1726.         cp->xmitted += usprintf (cp->fd, youare, stars, empty, cp->channel);
  1727.         return;
  1728.     }
  1729.     newchannel = atoi (s);
  1730.     /*    if(newchannel < 0 || newchannel > MAXCHANNEL) {        */
  1731.     if (newchannel < 0) {
  1732.         convcolorchange (cp, SYSCOLORS);
  1733.         cp->xmitted += usprintf (cp->fd, cnumber, MAXCHANNEL);
  1734.         return;
  1735.     }
  1736.     if (newchannel == cp->channel) {
  1737.         convcolorchange (cp, SYSCOLORS);
  1738.         cp->xmitted += usprintf (cp->fd, youare, stars, "already ", cp->channel);
  1739.         return;
  1740.     }
  1741.     if (gatekeeper (cp, newchannel))
  1742.         return;
  1743.     oldchannel = cp->channel;
  1744.     cp->channel = newchannel;
  1745.     cp->nettime = time (&cp->nettime);
  1746.     cp->locked = 1;        /* for bump command    */
  1747.     mystatus (cp, oldchannel);
  1748. }
  1749.  
  1750.  
  1751.  
  1752. static void
  1753. accept_command (struct convection *cp)
  1754. {
  1755.     if (cp->paged == -1) {
  1756.         convcolorchange (cp, SYSCOLORS);
  1757.         cp->xmitted += usprintf (cp->fd, "??? %s\n", channelstr);
  1758.     } else {
  1759.         sprintf (cp->ibuf, "/c %d", cp->paged);
  1760.         setparamptr (cp, &cp->ibuf[3]);
  1761.         channel_command (cp);
  1762.     }
  1763. }
  1764.  
  1765.  
  1766.  
  1767. static void
  1768. help_command (struct convection *cp)
  1769. {
  1770. int k;
  1771. char *cptr;
  1772. char const *file2open = 0;
  1773.  
  1774.     (void) sockblock (cp->fd, SOCK_BLOCK);
  1775.     cptr = getparam (cp);
  1776.  
  1777.     file2open = (tolower (*cptr) != 'n') ? ConfHlp : (tolower (cptr[2]) == 'w') ? ConfNews : NetControlHlp;
  1778.     convcolorchange (cp, INFOCOLORS);
  1779.     k = DisplayFile (file2open, cp->fd);
  1780.     if (k)
  1781.         cp->xmitted += k;
  1782.     else {
  1783.         convcolorchange (cp, SYSCOLORS);
  1784.         cp->xmitted += usprintf (cp->fd, noopenstr, file2open);
  1785.     }
  1786.     cp->xmitted += usprintf (cp->fd, trailer);
  1787.     (void) sockblock (cp->fd, SOCK_NOTXBLOCK);
  1788. }
  1789.  
  1790.  
  1791.  
  1792. static void
  1793. news_command (struct convection *cp)
  1794. {
  1795.     strcpy (cp->ibuf, "h news");
  1796.     setparamptr (cp, &cp->ibuf[2]);
  1797.     help_command (cp);
  1798. }
  1799.  
  1800.  
  1801.  
  1802. static void
  1803. invite_command (struct convection *cp)
  1804. {
  1805. struct group *gp;
  1806. char *toname, *chk, *cp2;
  1807.  
  1808.     toname = getparam (cp);
  1809.     chk = getparamline (cp);
  1810.     if (*chk)
  1811.         chk[51] = 0;
  1812.  
  1813.     if (*toname) {
  1814.         if ((cp2 = strchr (toname, '@')) != NULLCHAR)
  1815.             *cp2 = '\0';
  1816.         gp = find_group (cp->channel);
  1817.         if (gp && gp->private && cp->net != cp->channel) {
  1818.             convcolorchange (cp, SYSCOLORS);
  1819.             cp->xmitted += usprintf (cp->fd, noinvite, stars, privatestr, netcontrolstr);
  1820.         } else
  1821.             send_invite_msg (cp->name, toname, cp->channel, chk);
  1822.     }
  1823. }
  1824.  
  1825.  
  1826.  
  1827. static char *
  1828. ts4 (time_t seconds)
  1829. {
  1830. int days, hours, minutes;
  1831. static char buffer[50];
  1832. char buf[20];
  1833.  
  1834.     days = (int) (seconds / 86400);
  1835.     seconds -= days * 86400;
  1836.     hours = (int) (seconds / 3600);
  1837.     seconds -= hours * 3600;
  1838.     minutes = (int) (seconds / 60);
  1839.     seconds -= minutes * 60;
  1840.     buffer[0] = '\0';
  1841.     if (days) {
  1842.         sprintf (buf, "%d day%s, ", days, (days == 1) ? "" : "s");
  1843.         strncpy (buffer, buf, 50);
  1844.     }
  1845.     if (days + hours) {
  1846.         sprintf (buf, "%d hour%s, ", hours, (hours == 1) ? "" : "s");
  1847.         strcat (buffer, buf);
  1848.     }
  1849.     if (days + hours + minutes) {
  1850.         sprintf (buf, "%d minute%s, ", minutes, (minutes == 1) ? "" : "s");
  1851.         strcat (buffer, buf);
  1852.     }
  1853.     sprintf (buf, "%ld second%s.", seconds, (seconds == 1) ? "" : "s");
  1854.     strcat (buffer, buf);
  1855.     return buffer;
  1856. }
  1857.  
  1858.  
  1859.  
  1860. static char *
  1861. ts3 (time_t seconds, char *buffer)
  1862. {
  1863.     if (seconds < 100)
  1864.         sprintf (buffer, "%lds", seconds);
  1865.     else if (seconds < 6000)
  1866.         sprintf (buffer, "%ldm", seconds / 60);
  1867.     else if (seconds < 360000)
  1868.         sprintf (buffer, "%ldh", seconds / 3600);
  1869.     else
  1870.         sprintf (buffer, "%ldd", seconds / 86400);
  1871.     return buffer;
  1872. }
  1873.  
  1874.  
  1875.  
  1876. int 
  1877. ShowConfLinks2 (int s, char *user, int full)
  1878. {
  1879. int num = 0;
  1880. struct convection *pc;
  1881. struct permlink *pp;
  1882. char buffer[100], tmp[20], tmp2[64], tmp3[64], tmp4[64];
  1883.  
  1884.     sprintf (buffer, "Host       State        Quality Software  Since%s",
  1885.          (full) ? " NextTry Tries Queue    RX    TX" : "");
  1886.     if (user) {
  1887.         clear_locks ();
  1888.         send_msg_to_user (conversd, user, buffer);
  1889.     } else
  1890.         num += usprintf (s, "%s\n", buffer);
  1891.     for (pc = convections; pc; pc = pc->next) {
  1892.         kwait (NULL);
  1893.         strcpy (tmp2, "  ---  ");
  1894.         for (pp = permlinks; pp; pp = pp->next) {
  1895.             if (pp->convection == pc) {
  1896.                 if (pp->txtime || pp->rxtime) {
  1897.                     if (pp->rxtime == (time_t) -1)
  1898.                         sprintf (tmp2, "  %3s  ", ts3 (pp->txtime, tmp3));
  1899.                     else
  1900.                         sprintf (tmp2, "%3s/%-3s", ts3 (pp->txtime, tmp3), ts3 (pp->rxtime, tmp4));
  1901.                 }
  1902.                 break;
  1903.             }
  1904.         }
  1905.         if (pc->type == CT_HOST) {
  1906.             sprintf (buffer,
  1907.                  (full) ?
  1908.                  "%-10.10s Connected    %7.7s %8.8s %s               %5d %4dK %4dK" :
  1909.                  "%-10.10s Connected    %7.7s %8.8s %s",
  1910.                  pc->name, tmp2, (pp) ? pp->rev : "",
  1911.                  timestring (pc->time),
  1912.                  socklen (pc->fd, 1),
  1913.                  (pc->received / 1024),
  1914.                  (pc->xmitted / 1024));
  1915.             if (user) {
  1916.                 clear_locks ();
  1917.                 send_msg_to_user (conversd, user, buffer);
  1918.             } else
  1919.                 num += usprintf (s, "%s\n", buffer);
  1920.         }
  1921.     }
  1922.  
  1923.     for (pp = permlinks; pp; pp = pp->next) {
  1924.         kwait (NULL);
  1925.         if (!pp->convection || pp->convection->type != CT_HOST) {
  1926.             strcpy (tmp, timestring (pp->retrytime));
  1927.             sprintf (buffer,
  1928.                  (full) ?
  1929.                 "%-10.10s %-12.12s   ---   %8.8s %s %s  %5d\n" :
  1930.                  "%-10.10s %-12.12s   ---   %8.8s %s",
  1931.                  pp->name,
  1932.                  pp->convection ? "Connecting" : "Disconnected",
  1933.                  pp->rev, timestring (pp->statetime),
  1934.                  tmp,
  1935.                  pp->tries);
  1936.             if (user) {
  1937.                 clear_locks ();
  1938.                 send_msg_to_user (conversd, user, buffer);
  1939.             } else
  1940.                 num += usprintf (s, "%s\n", buffer);
  1941.         }
  1942.     }
  1943.     return num;
  1944. }
  1945.  
  1946.  
  1947.  
  1948. int 
  1949. ShowConfLinks (int s, int full)
  1950. {
  1951.     return (ShowConfLinks2 (s, NULLCHAR, full));
  1952. }
  1953.  
  1954.  
  1955.  
  1956. static void
  1957. cstat_command (struct convection *cp)
  1958. {
  1959.     cp->xmitted += ShowConfLinks (cp->fd, 1);
  1960.     cp->xmitted += usprintf (cp->fd, "\n");
  1961.     cp->xmitted += ShowConfDest (cp->fd, "", cp->name);
  1962.     cp->xmitted += usprintf (cp->fd, "%s\n", stars);
  1963. }
  1964.  
  1965.  
  1966.  
  1967. static void
  1968. links_command (struct convection *cp)
  1969. {
  1970. char *host;
  1971. struct convection *p;
  1972.  
  1973.     host = getparam (cp);
  1974.     if (*host && stricmp (host, Chostname)) {
  1975.         for (p = convections; p; p = p->next)
  1976.             if (p->type == CT_HOST)
  1977.                 p->xmitted += usprintf (p->fd, "/\377\200LINK %s %s\n", cp->name, host);
  1978.     } else {
  1979.         cp->xmitted += ShowConfLinks (cp->fd, 1);
  1980.         cp->xmitted += usprintf (cp->fd, "***\n");
  1981.     }
  1982.     return;
  1983. }
  1984.  
  1985.  
  1986.  
  1987. static void
  1988. h_link_command (struct convection *cp)
  1989. {
  1990. char *name, *host, buffer[100];
  1991.  
  1992.     name = getparam (cp);
  1993.     host = getparam (cp);
  1994.     if (stricmp (host, Chostname))
  1995.         return;
  1996.     sprintf (buffer, "*** Links at %s", Chostname);
  1997.     clear_locks ();
  1998.     send_msg_to_user (conversd, name, buffer);
  1999.     (void) ShowConfLinks2 (0, name, 1);
  2000.     clear_locks ();
  2001.     send_msg_to_user (conversd, name, "***");
  2002. }
  2003.  
  2004.  
  2005.  
  2006. static void
  2007. msg_command (struct convection *cp)
  2008. {
  2009. char *toname, *text;
  2010. register struct convection *p;
  2011. char buf[(NAMELEN * 2) + 2];
  2012.  
  2013.     toname = getparam (cp);
  2014.     text = getparamline (cp);
  2015.  
  2016.     if (!*text)
  2017.         return;
  2018.     for (p = convections; p; p = p->next)
  2019.         if (p->type == CT_USER && (!strcmpi (p->name, toname) || !strcmpi (p->nickname, toname))) {
  2020.             getTXname (cp, buf);
  2021.             send_msg_to_user (buf, toname, text);
  2022.             return;
  2023.         }
  2024.     convcolorchange (cp, SYSCOLORS);
  2025.     cp->xmitted += usprintf (cp->fd, nosuchuser, stars, toname);
  2026. }
  2027.  
  2028.  
  2029.  
  2030. static void
  2031. announce_new_user (struct convection *cp)
  2032. {
  2033. char dummy[80];
  2034. register struct group *gp;
  2035. int numgroups;
  2036.  
  2037.     if (CountConfUsers () > 1) {
  2038.         cp->xmitted += usprintf (cp->fd, online, stars, CountConfUsers ());
  2039.         if ((numgroups = CountConfGroups ()) != 0)
  2040.             cp->xmitted += usprintf (cp->fd, groupsavail, stars, (numgroups > 1) ? "are" : "is", numgroups, (numgroups > 1) ? "s" : empty);
  2041.     }
  2042.     sprintf (dummy, newuserstr, stars, cp->name, cp->channel);
  2043.     for (gp = groups; gp; gp = gp->next)
  2044.         if (gp->channel != cp->channel)
  2045.             send_msg_to_user (conversd, gp->moderator, dummy);
  2046.     send_user_change_msg (cp->name, cp->host, cp->time, -1, cp->channel, cp->data);
  2047. }
  2048.  
  2049.  
  2050.  
  2051. static void
  2052. color_command (struct convection *cp)
  2053. {
  2054. char *dummy;
  2055.  
  2056.     dummy = getparam (cp);
  2057.     if (*dummy) {
  2058.         if (!stricmp (dummy, "on"))
  2059.             cp->flags |= USE_COLOR;
  2060.         if (!stricmp (dummy, "off"))
  2061.             cp->flags &= ~USE_COLOR;
  2062.     }
  2063.     cp->colorset[0] = '\0';
  2064.     convcolorchange (cp, SYSCOLORS);
  2065.     cp->xmitted += usprintf (cp->fd, colorstatus, stars, (cp->flags & USE_COLOR) ? n_str : ff_str);
  2066.     cp->flags |= CHANGED_INFO;
  2067. }
  2068.  
  2069.  
  2070.  
  2071. /* save the personal information for this user */
  2072. static void 
  2073. save_personal (struct convection *cp)
  2074. {
  2075. FILE *old, *new;
  2076. char *newname;
  2077. int found = 0;
  2078.  
  2079.     if ((!cp->nickname[0] && !cp->data) || !(cp->flags & CHANGED_INFO))
  2080.         return;
  2081.     if ((old = fopen (ConfInfo, UPDATE_TEXT)) == NULL)
  2082.         if ((old = fopen (ConfInfo, CREATE_TEXT)) == NULL)
  2083.             return;
  2084.     rewind (old);
  2085.     newname = (char *) mallocw (strlen (ConfInfo) + 5);
  2086.     sprintf (newname, "%s.new", ConfInfo);
  2087.     if ((new = fopen (newname, CREATE_TEXT)) == NULLFILE) {
  2088.         (void) fclose (old);
  2089.         free (newname);
  2090.         return;
  2091.     }
  2092.     while (fgets (cp->ibuf, LINELEN, old) != NULLCHAR) {
  2093.         kwait (NULL);
  2094.         rip (cp->ibuf);
  2095.         if (!stricmp (cp->ibuf, cp->name)) {
  2096.             found = 1;
  2097.             for (;;) {
  2098.                 if (fgets (cp->ibuf, LINELEN, old) == NULLCHAR)
  2099.                     break;
  2100.                 if (cp->ibuf[0] != ' ') {
  2101.                     /*                    fputs (cp->ibuf, new);        */
  2102.                     break;
  2103.                 }
  2104.             }
  2105.             break;
  2106.         }
  2107.         fprintf (new, fullstrcr, cp->ibuf);
  2108.     }
  2109.     fprintf (new, fullstrcr, cp->name);
  2110.     if (*cp->nickname)
  2111.         fprintf (new, " nickname %s\n", cp->nickname);
  2112.     if (cp->data)
  2113.         fprintf (new, " personal %s\n", cp->data);
  2114.     if (cp->flags & USE_COLOR)
  2115.         fprintf (new, " color ON\n");
  2116.     if (found)        /* add rest of file */
  2117.         do {
  2118.             fputs (cp->ibuf, new);
  2119.         } while (fgets (cp->ibuf, LINELEN, old) != NULLCHAR);
  2120.     (void) fclose (new);
  2121.     (void) fclose (old);
  2122.     unlink (ConfInfo);
  2123.     (void) rename (newname, ConfInfo);
  2124.     free (newname);
  2125.     return;
  2126. }
  2127.  
  2128.  
  2129.  
  2130. /* find the personal information for this user */
  2131. static void 
  2132. set_personal (struct convection *cp)
  2133. {
  2134. FILE *fp;
  2135.  
  2136.     if ((fp = fopen (ConfInfo, READ_TEXT)) == NULL)
  2137.         return;
  2138.     while (fgets (cp->ibuf, LINELEN, fp) != NULL) {
  2139.         kwait (NULL);
  2140.         if (*(cp->ibuf) == ' ')
  2141.             continue;
  2142.         rip (cp->ibuf);
  2143.         if (stricmp (cp->name, cp->ibuf))
  2144.             continue;
  2145.         if (fgets (cp->ibuf, LINELEN, fp) != NULL) {
  2146.             if (!strnicmp (cp->ibuf, " nick", 5)) {
  2147.                 /* Found nickname data ! */
  2148.                 setparamptr (cp, &cp->ibuf[1]);
  2149.                 (void) getparam (cp);
  2150.                 nickname_command (cp);
  2151.                 (void) fgets (cp->ibuf, LINELEN, fp);
  2152.             }
  2153.             if (!strnicmp (cp->ibuf, " pers", 5)) {
  2154.                 /* Found personal data ! */
  2155.                 setparamptr (cp, &cp->ibuf[1]);
  2156.                 (void) getparam (cp);
  2157.                 personal_command (cp);
  2158.                 (void) fgets (cp->ibuf, LINELEN, fp);
  2159.             }
  2160.             if (!strnicmp (cp->ibuf, " color", 6)) {
  2161.                 /* Found color data ! */
  2162.                 setparamptr (cp, &cp->ibuf[1]);
  2163.                 (void) getparam (cp);
  2164.                 color_command (cp);
  2165.             }
  2166.             cp->xmitted += usprintf (cp->fd, welcomeback, stars, cp->nickname);
  2167.         }
  2168.     }
  2169.     (void) fclose (fp);
  2170.     return;
  2171. }
  2172.  
  2173.  
  2174.  
  2175. static void
  2176. name_command (struct convection *cp)
  2177. {
  2178. int newchannel;
  2179. char *dummy, *name;
  2180.  
  2181.     name = getparam (cp);
  2182.     if (!*name)
  2183.         return;
  2184.  
  2185.     dummy = getparam (cp);
  2186.     if (*dummy)
  2187.         newchannel = atoi (dummy);
  2188.     else
  2189.         newchannel = CChannel;
  2190.     
  2191.     strncpy (cp->name, name, NAMELEN);
  2192.     strncpy (cp->nickname, name, NAMELEN);
  2193.     (void) strlwr (cp->name);
  2194.  
  2195.     strncpy (cp->host, Chostname, NAMELEN);
  2196.     cp->type = CT_USER;
  2197.     cp->channel = (newchannel == -1) ? CChannel : newchannel;
  2198.  
  2199.     announce_new_user (cp);
  2200.     set_personal (cp);
  2201.     cp->flags &= ~CHANGED_INFO;
  2202.     mystatus (cp, (int) -1);
  2203. }
  2204.  
  2205.  
  2206.  
  2207. #ifdef LZW
  2208. /* Set or show the status of the 'compressed' flag - KO4KS */
  2209. static void
  2210. compressed_command (struct convection *cp)
  2211. {
  2212. char *cp2;
  2213. struct usock *up;
  2214.  
  2215.     cp2 = getparam (cp);
  2216.     if (*cp2) {
  2217.         if (*cp2 == 'o' || *cp2 == 'O') {    /* There is an argument */
  2218.             if (cp2[1] == 'f' || cp2[1] == 'F')    /* Turn it off */
  2219.                 cp->flags &= ~USE_LZW;
  2220.             else
  2221.                 cp->flags |= USE_LZW;
  2222.             up = itop (cp->fd);
  2223.             if ((cp->flags & USE_LZW) || (up->zout != NULLLZW))
  2224.                 togglelzw (cp->fd, cp->flags & USE_LZW);
  2225.  
  2226.         }
  2227.     }
  2228.     convcolorchange (cp, SYSCOLORS);
  2229.     usprintf (cp->fd, "%sStream compression o%s\n", stars, (cp->flags & USE_LZW) ? n_str : ff_str);
  2230.     return;
  2231. }
  2232.  
  2233. #endif
  2234.  
  2235.  
  2236.  
  2237. /* Set or show the status of the 'sound' flag - WG7J */
  2238. static void
  2239. sounds_command (struct convection *cp)
  2240. {
  2241. char *cp2;
  2242.  
  2243.     cp2 = getparam (cp);
  2244.     if (*cp2) {
  2245.         if (*cp2 == 'o' || *cp2 == 'O') {    /* There is an argument */
  2246.             if (cp2[1] == 'f' || cp2[1] == 'F')    /* Turn it off */
  2247.                 cp->flags &= ~USE_SOUND;
  2248.             else
  2249.                 cp->flags |= USE_SOUND;
  2250.         }
  2251.     }
  2252.     convcolorchange (cp, SYSCOLORS);
  2253.     usprintf (cp->fd, "%sSounds o%s\n", stars, (cp->flags & USE_SOUND) ? n_str : ff_str);
  2254.     return;
  2255. }
  2256.  
  2257.  
  2258.  
  2259. /* Send updated net data */
  2260. static void
  2261. update_net_data (struct group *gp)
  2262. {
  2263. struct convection *p;
  2264. time_t currtime;
  2265.  
  2266.     currtime = time (&currtime);
  2267.     /* update all links */
  2268.     for (p = convections; p; p = p->next) {
  2269.         kwait (NULL);
  2270.         if (p->type == CT_HOST) {
  2271.             p->xmitted += usprintf (p->fd, ndatstr,
  2272.                         gp->channel, gp->private, gp->logged, gp->nextq, gp->totalq,
  2273.                      gp->name, gp->moderator, gp->password);
  2274.             p->xmitted += usprintf (p->fd, topicstr,
  2275.                         gp->moderator, Chostname, currtime, gp->channel, gp->name);
  2276.         }
  2277.     }
  2278. }
  2279.  
  2280.  
  2281.  
  2282. /* Send updated personal data, nickname */
  2283. static void
  2284. update_user_data (struct convection *cp, int personal)
  2285. {
  2286. struct convection *p;
  2287.  
  2288.     /* update all links */
  2289.     for (p = convections; p; p = p->next) {
  2290.         kwait (NULL);
  2291.         if (p->type == CT_HOST) {
  2292.             if (personal)
  2293.                 send_user_change_msg (cp->name, cp->host, cp->time, cp->channel, cp->channel, cp->data);
  2294.             if (p->features & FEATURE_NICK)
  2295.                 p->xmitted += usprintf (p->fd, uaddstr,
  2296.                             cp->name, cp->host, cp->nickname, cp->net, (cp->data) ? cp->data : "~~");
  2297.         }
  2298.     }
  2299. }
  2300.  
  2301.  
  2302.  
  2303. static int
  2304. ShowConfDest (int s, const char *dest, const char *name)
  2305. {
  2306. char tmp[64];
  2307. struct destination *d;
  2308. int i = 1;
  2309. int xmitted = 0;
  2310.  
  2311.     if (*dest == '\0') {
  2312.         for (d = destinations; d; d = d->next) {
  2313.             if (d->rtt) {
  2314.                 xmitted += usprintf (s, "%-9.9s (%8.8s) %3s", d->name, d->rev, ts3 (d->rtt, tmp));
  2315.                 if ((i == 3) || !(d->next)) {
  2316.                     xmitted += usprintf (s, "\n");
  2317.                     i = 0;
  2318.                 } else
  2319.                     xmitted += usprintf (s, "   ");
  2320.                 i++;
  2321.             }
  2322.         }
  2323.         if ((i != 1))
  2324.             xmitted += usprintf (s, "\n");
  2325.     } else {
  2326.         for (d = destinations; d; d = d->next) {
  2327.             if (!stricmp (d->name, dest)) {
  2328.                 clear_locks ();
  2329.                 xmitted = usprintf (s, "*** route: %s -> %s -> %s (%ld)\n", Chostname, d->link->name, dest, d->rtt);
  2330.                 if (stricmp (dest, d->link->name))
  2331.                     xmitted += usprintf (d->link->convection->fd, "/\377\200ROUT %s %s 99\n", dest, name);
  2332.                 break;
  2333.             }
  2334.         }
  2335.         if (d == NULLDESTINATION)
  2336.             xmitted += usprintf (s, "*** no route to %s\n", dest);
  2337.     }
  2338.     return xmitted;
  2339. }
  2340.  
  2341.  
  2342.  
  2343. void 
  2344. hosts_command (struct convection *cp)
  2345. {
  2346. char *dest;
  2347.  
  2348.     dest = getparam (cp);
  2349.     cp->xmitted += ShowConfDest (cp->fd, dest, cp->name);
  2350.     if (!*dest)
  2351.         cp->xmitted += usprintf (cp->fd, "%s\n", stars);
  2352. }
  2353.  
  2354.  
  2355.  
  2356. /* Set some personal data, like name and qth - WG7J */
  2357. static void
  2358. personal_command (struct convection *cp)
  2359. {
  2360. char *cptr;
  2361.  
  2362.     cptr = getparamline (cp);
  2363.     if (*cptr) {
  2364.         if (cp->data)
  2365.             free (cp->data);
  2366.         rip (cptr);    /* get rid of ending '\n' */
  2367.         cp->data = strdup (cptr);
  2368.         update_user_data (cp, 1);
  2369.         cp->flags |= CHANGED_INFO;
  2370.     }
  2371.     convcolorchange (cp, SYSCOLORS);
  2372.     cp->xmitted += usprintf (cp->fd, personalset, stars, (cp->data) ? cp->data : empty);
  2373. }
  2374.  
  2375.  
  2376.  
  2377. static void
  2378. nickname_command (struct convection *cp)
  2379. {
  2380. int nonick = 0, err = 0;
  2381.  
  2382.     convcolorchange (cp, SYSCOLORS);
  2383.     if (tolower (cp->ibuf[2]) == 'o') {
  2384.         nonick = 1;
  2385.         strncpy (cp->nickname, cp->name, NAMELEN);
  2386.     } else {
  2387.         char *new;
  2388.         new = getparam (cp);
  2389.         if (*new)
  2390.             if (strcmp (new, systemstr))
  2391.                 strncpy (cp->nickname, new, NAMELEN);
  2392.             else {
  2393.                 cp->xmitted += usprintf (cp->fd, nicknamestr, stars, nicknmstr, "can't be ", new);
  2394.                 err = 1;
  2395.             }
  2396.     }
  2397.     cp->xmitted += usprintf (cp->fd, nicknamestr, stars, nicknmstr, (nonick) ? "re" : empty, cp->nickname);
  2398.     if (!err)
  2399.         update_user_data (cp, 0);
  2400.     cp->flags |= CHANGED_INFO;
  2401. }
  2402.  
  2403.  
  2404.  
  2405. static void
  2406. password_command (struct convection *cp)
  2407. {
  2408. char *new;
  2409.  
  2410.     convcolorchange (cp, SYSCOLORS);
  2411.     if (tolower (cp->ibuf[2]) == 'o') {
  2412.         cp->password[0] = '\0';
  2413.         cp->xmitted += usprintf (cp->fd, "%s %s!\n", passwordstr, clearedstr);
  2414.         return;
  2415.     }
  2416.     new = getparam (cp);
  2417.     if (*new) {
  2418.         strncpy (cp->password, new, NAMELEN);
  2419.         cp->xmitted += usprintf (cp->fd, "%s%s is set!\n", stars, passwordstr);
  2420.     } else {
  2421.         if (cp->password[0])
  2422.             cp->xmitted += usprintf (cp->fd, "%s%s is '%s'.\n", stars,
  2423.                 passwordstr, cp->password);
  2424.         else
  2425.             cp->xmitted += usprintf (cp->fd, "%sNo %s in use.\n", stars, passwordstr);
  2426.     }
  2427. }
  2428.  
  2429.  
  2430.  
  2431. static int
  2432. isrosedigit (char c)
  2433. {
  2434. int retval;
  2435.  
  2436.     retval = isdigit (c);
  2437.     if (!retval)
  2438.         switch (tolower (c)) {
  2439.             case 'l':
  2440.             case 'o':
  2441.             case 'i':
  2442.                 retval = 1;
  2443.                 break;
  2444.             default:
  2445.                 break;
  2446.         }
  2447.     return retval;
  2448. }
  2449.  
  2450.  
  2451.  
  2452. static char *
  2453. getVia (char *call)
  2454. {
  2455. char tmp[AXBUF];
  2456. static char roseaddr[14];
  2457. int i, k;
  2458. register struct ax_route *axr;
  2459.  
  2460.     roseaddr[0] = 0;
  2461.     for (axr = Ax_routes; axr != NULLAXR; axr = axr->next) {
  2462.         (void) pax25 (tmp, axr->target);
  2463.         if (!strnicmp (call, tmp, strlen (call))) {
  2464.             for (i = 0; i < axr->ndigis; i++) {
  2465.                 (void) pax25 (tmp, axr->digis[i]);
  2466.                 if (strlen (tmp) != 6)
  2467.                     continue;
  2468.                 for (k = 0; k < 6; k++) {
  2469.                     if (!isrosedigit (tmp[k]))
  2470.                         break;
  2471.                 }
  2472.                 if (k != 6)
  2473.                     continue;
  2474.                 sprintf (roseaddr, "ROSE:%-6.6s", tmp);
  2475.                 return (roseaddr);
  2476.             }
  2477.             break;
  2478.         }
  2479.     }
  2480.     return (roseaddr);
  2481. }
  2482.  
  2483.  
  2484.  
  2485. /* this is called from the finger-daemon when 'conf' is fingered - WG7J */
  2486. int 
  2487. ShowConfUsers (int s, char *athost)
  2488. {
  2489. struct convection *p;
  2490. int cnt;
  2491. int next_channel, channel = 0;
  2492.  
  2493.     cnt = usprintf (s, headerstr);
  2494.     next_channel = 0;
  2495.     clear_locks ();
  2496.     do {
  2497.         channel = next_channel;
  2498.         next_channel = 0;
  2499.         for (p = convections; p; p = p->next) {
  2500.             kwait (NULL);
  2501.             if (p->type == CT_USER && !p->locked) {
  2502.                 if (athost && strnicmp (athost, p->host, strlen (athost)))
  2503.                     continue;
  2504.                 if (channel < p->channel) {
  2505.                     if (next_channel) {
  2506.                         if (p->channel < next_channel)
  2507.                             next_channel = p->channel;
  2508.                     } else
  2509.                         next_channel = p->channel;
  2510.                 } else if (channel == p->channel) {
  2511.                     cnt += usprintf (s, userdata, p->name, p->host, (p->via) ? p->via->name : getVia (p->name),
  2512.                              p->channel, timestring (p->time), (p->data) ? p->data : empty);
  2513.                     usflush (s);    /* might not be neccesary */
  2514.                     p->locked = 1;
  2515.                 }
  2516.             }
  2517.         }
  2518.     } while (next_channel > channel);
  2519.     return (cnt);
  2520. }
  2521.  
  2522.  
  2523.  
  2524. int 
  2525. CountConfUsers (void)
  2526. {
  2527. struct convection *p;
  2528. int cnt = 0;
  2529.  
  2530.     for (p = convections; p; p = p->next)
  2531.         if (p->type == CT_USER)
  2532.             cnt++;
  2533.     return (cnt);
  2534. }
  2535.  
  2536.  
  2537.  
  2538. static int 
  2539. CountConfGroups (void)
  2540. {
  2541. int cnt = 0;
  2542. register struct group *gp;
  2543.  
  2544.     for (gp = groups; gp; gp = gp->next)
  2545.         cnt++;
  2546.     return (cnt);
  2547. }
  2548.  
  2549.  
  2550.  
  2551. #ifdef ALLSERV
  2552. static void
  2553. quote_command (struct convection *cp OPTIONAL)
  2554. {
  2555. char *p;
  2556.  
  2557.     p = getquote ();
  2558.     if (p) {
  2559.         clear_locks ();
  2560.         send_msg_to_channel (conversd, cp->channel, quotebanner);
  2561.         clear_locks ();
  2562.         send_msg_to_channel (conversd, cp->channel, p);
  2563.         clear_locks ();
  2564.         send_msg_to_channel (conversd, cp->channel, trailer);
  2565.         free (p);
  2566.     }
  2567. }
  2568. #endif
  2569.  
  2570.  
  2571.  
  2572. static void
  2573. list_command (struct convection *cp)
  2574. {
  2575. char buffer[80];
  2576. struct convection *p;
  2577. int channel;
  2578. int next_channel, header;
  2579. struct group *gp;
  2580. char buf[(NAMELEN * 2) + 2];
  2581.  
  2582.     cp->xmitted += usprintf (cp->fd, "%s  %ss\n", channelstr, userstr);
  2583.     next_channel = 0;
  2584.     clear_locks ();
  2585.     do {
  2586.         channel = next_channel;
  2587.         next_channel = 0;
  2588.         header = 0;
  2589.         for (p = convections; p; p = p->next) {
  2590.             kwait (NULL);
  2591.             if (p->type == CT_USER && !p->locked) {
  2592.                 if (channel < p->channel) {
  2593.                     if (next_channel) {
  2594.                         if (p->channel < next_channel)
  2595.                             next_channel = p->channel;
  2596.                     } else
  2597.                         next_channel = p->channel;
  2598.                 } else if (channel == p->channel) {
  2599.                     if (!header) {
  2600.                         header = 1;
  2601.                         sprintf (buffer, "%7d ", channel);
  2602.                         if ((gp = find_group (channel)) != NULLGROUP) {
  2603.                             sprintf (&buffer[8], "       %s", gp->name);
  2604.                             cp->xmitted += usprintf (cp->fd, fullstrcr, buffer);
  2605.                             strcpy (buffer, "        ");
  2606.                         }
  2607.                     }
  2608.                     strcat (buffer, " ");
  2609.                     if (strlen (buffer) > 65) {
  2610.                         cp->xmitted += usprintf (cp->fd, fullstrcr, buffer);
  2611.                         strcpy (buffer, "         ");
  2612.                     }
  2613.                     getTXname (p, buf);
  2614.                     strcat (buffer, buf);
  2615.                     p->locked = 1;
  2616.                 }
  2617.             }
  2618.         }
  2619.         if (header)
  2620.             cp->xmitted += usprintf (cp->fd, fullstrcr, buffer);
  2621.     } while (next_channel > channel);
  2622. }
  2623.  
  2624.  
  2625.  
  2626. static void
  2627. who_command (struct convection *cp)
  2628. {
  2629. char *buffer, buf[(NAMELEN * 2) + 2];
  2630. int next_channel, channel = 0, quick = 0, realname = 0, here = 0;
  2631. struct convection *p;
  2632. struct group *gp;
  2633. char *whois;
  2634. char *athost = NULLCHAR;
  2635. #ifdef MAILBOX
  2636. int i;
  2637. struct mbx *m = 0;
  2638. #endif
  2639.  
  2640.     convcolorchange (cp, INFOCOLORS);
  2641.     buffer = getparam (cp);
  2642.     whois = getparam (cp);
  2643.     switch (tolower (buffer[0])) {
  2644.         case 'q':
  2645.             quick = 1;
  2646.             break;
  2647.         case 'n':
  2648.             quick = 0;
  2649.             break;
  2650.         case 'r':
  2651.             realname = 1;
  2652.             break;
  2653.         case '@':
  2654.             athost = whois;
  2655.             break;
  2656.         case '*':
  2657.             here = 1;
  2658.             channel = cp->channel;
  2659.             break;
  2660.         default:
  2661.             if (buffer[0] == '0') {
  2662.                 here = 1;
  2663.                 channel = 0;
  2664.             } else if ((channel = atoi (buffer)) != 0)
  2665.                 here = 1;
  2666.             else
  2667.                 quick = 1;
  2668.     }
  2669.  
  2670.     if (quick)
  2671.         list_command (cp);
  2672.     else if (here) {
  2673.         cp->xmitted += usprintf (cp->fd, "%s  %ss\n", channelstr, userstr);
  2674.         sprintf (buffer, "%7d ", channel);
  2675.         if ((gp = find_group (channel)) != NULLGROUP) {
  2676.             sprintf (&buffer[8], "       %s", gp->name);
  2677.             cp->xmitted += usprintf (cp->fd, fullstrcr, buffer);
  2678.             strcpy (buffer, "        ");
  2679.         }
  2680.         for (p = convections; p; p = p->next) {
  2681.             kwait (NULL);
  2682.             if (p->type == CT_USER && p->channel == channel) {
  2683.                 strcat (buffer, " ");
  2684.                 if (strlen (buffer) > 65) {
  2685.                     cp->xmitted += usprintf (cp->fd, fullstrcr, buffer);
  2686.                     strcpy (buffer, "         ");
  2687.                 }
  2688.                 getTXname (p, buf);
  2689.                 strcat (buffer, buf);
  2690.             }
  2691.         }
  2692.         cp->xmitted += usprintf (cp->fd, fullstrcr, buffer);
  2693.         quick = 1;
  2694.     } else if (realname) {
  2695.         cp->xmitted += usprintf (cp->fd, whobanner, userstr, nicknmstr, channelstr);
  2696.         next_channel = 0;
  2697.         clear_locks ();
  2698.         do {
  2699.             channel = next_channel;
  2700.             next_channel = 0;
  2701.             for (p = convections; p; p = p->next) {
  2702.                 kwait (NULL);
  2703.                 if (p->type == CT_USER && !p->locked) {
  2704.                     if (channel < p->channel) {
  2705.                         if (next_channel) {
  2706.                             if (p->channel < next_channel)
  2707.                                 next_channel = p->channel;
  2708.                         } else
  2709.                             next_channel = p->channel;
  2710.                     } else {
  2711.                         if (!*whois || !strnicmp (whois, p->nickname, strlen (whois)) || !strnicmp (whois, p->name, strlen (whois)))
  2712.                             cp->xmitted += usprintf (cp->fd, "%-16.16s %-16.16s %7d %s\n",
  2713.                                          p->name, (!stricmp (p->name, p->nickname)) ? "" : p->nickname, p->channel, (p->data) ? p->data : empty);
  2714.                         p->locked = 1;
  2715.                     }
  2716.                 }
  2717.             }
  2718.         } while (next_channel > channel);
  2719.     } else
  2720.         cp->xmitted += ShowConfUsers (cp->fd, athost);
  2721.  
  2722. #ifdef MAILBOX
  2723.     if (!realname) {
  2724.         cp->xmitted += usprintf (cp->fd, "\nPBBS/NODE %ss\n", userstr);
  2725.         for (i = 0; i < NUMMBX; i++)
  2726.             if ((m = Mbox[i]) != NULLMBX) {
  2727.                 realname = 1;    /* we found one! */
  2728.                 if (quick)
  2729.                     cp->xmitted += usprintf (cp->fd, " BBS %-16s (%s)\n", m->name, displayMBstatus (m->state, 0));
  2730.                 else
  2731.                     cp->xmitted += usprintf (cp->fd, "%-16s BBS@%-32s (%s)\n", m->name, Hostname, displayMBstatus (m->state, 0));
  2732.             }
  2733.         if (!realname)
  2734.             cp->xmitted += usprintf (cp->fd, "(none)\n");
  2735.     }
  2736. #endif
  2737.     cp->xmitted += usprintf (cp->fd, trailer);
  2738. }
  2739.  
  2740.  
  2741.  
  2742. static void
  2743. imsg_command (struct convection *cp)
  2744. {
  2745. char *toname, *text;
  2746. struct convection *p, *q;
  2747. char buf[(NAMELEN * 2) + 2];
  2748.  
  2749.     toname = getparam (cp);
  2750.     text = getparamline (cp);
  2751.     if (!*text)
  2752.         return;
  2753.  
  2754.     for (p = convections; p; p = p->next) {
  2755.         if (p->type == CT_USER && p->channel == cp->channel && stricmp (p->name, toname) != 0 && stricmp (p->nickname, toname) != 0) {
  2756.             getTXname (cp, buf);
  2757.             send_msg_to_user (buf, p->name, text);
  2758.             q = p->next;
  2759.             while (q) {
  2760.                 if (!strcmp (p->name, q->name))
  2761.                     q->locked = 1;
  2762.                 q = q->next;
  2763.             }
  2764.         }
  2765.         if (p->via)
  2766.             p->via->locked = 0;
  2767.     }
  2768. }
  2769.  
  2770.  
  2771.  
  2772. static void
  2773. me_command (struct convection *cp)
  2774. {
  2775. char *text;
  2776. char buffer[LINELEN + (NAMELEN * 2) + 7];
  2777.  
  2778.     text = getparamline(cp);
  2779.     if (*text) {
  2780.         cp->locked = 1;
  2781.         sprintf (buffer, "%s%s@%s %s", stars, cp->name, cp->host, text);
  2782.         send_msg_to_channel ("conversd", cp->channel, buffer);
  2783.     }
  2784. }
  2785.  
  2786.  
  2787.  
  2788. static void
  2789. realname_command (struct convection *cp)
  2790. {
  2791. char name[LINELEN];
  2792.  
  2793.     strncpy (name, getparam (cp), LINELEN);
  2794.     sprintf (cp->ibuf, "/w r %s", name);
  2795.     setparamptr (cp, &cp->ibuf[3]);
  2796.     who_command (cp);
  2797. }
  2798.  
  2799.  
  2800.  
  2801. static void
  2802. h_dest_command (struct convection *cp)
  2803. {
  2804. char *name, *rev;
  2805. int rtt;
  2806. struct permlink *l;
  2807.  
  2808.     name = getparam (cp);
  2809.     rev = getparam (cp);
  2810.     if (*rev)
  2811.         return;
  2812.     rtt = atoi (rev);
  2813.     rev = getparam (cp);
  2814.     
  2815.     if (!stricmp (name, Chostname))
  2816.         return;
  2817.  
  2818.     for (l = permlinks; l; l = l->next) {
  2819.         if (l->convection && (l->convection == cp))
  2820.             break;
  2821.     }
  2822.     if (l)
  2823.         update_destinations (l, name, rtt, rev);
  2824. }
  2825.  
  2826.  
  2827.  
  2828. static void 
  2829. update_destinations (struct permlink *p, char *name, long rtt, const char *rev)
  2830. {
  2831. struct permlink *l;
  2832. struct destination *d, *d1;
  2833. char buffer[256];
  2834.  
  2835.     for (d = destinations; d; d = d->next)
  2836.         if (!stricmp (d->name, name))
  2837.             break;
  2838.  
  2839.     if (!d) {
  2840.         d = (struct destination *) mallocw (sizeof (struct destination));
  2841.  
  2842.         if (d) {
  2843.             d->last_sent_rtt = 0;
  2844.             d->link = p;
  2845.             strncpy (d->name, name, NAMELEN);
  2846.             strncpy (d->rev, rev, NAMELEN);
  2847.             if (!destinations || (!destinations->name) || (strcmp (destinations->name, name) > 0)) {
  2848.                 d->next = destinations;
  2849.                 destinations = d;
  2850.             } else {
  2851.                 d1 = destinations;
  2852.                 while (d1->next) {
  2853.                     if (stricmp (d1->next->name, name) > 0) {
  2854.                         d->next = d1->next;
  2855.                         d1->next = d;
  2856.                         break;
  2857.                     }
  2858.                     d1 = d1->next;
  2859.                 }
  2860.                 if (!d1->next) {
  2861.                     d->next = d1->next;
  2862.                     d1->next = d;
  2863.                 }
  2864.             }
  2865.         }
  2866.     } else {
  2867.         strncpy (d->rev, rev, NAMELEN);
  2868.         d->link = p;
  2869.     }
  2870.     if (!d)
  2871.         return;
  2872.  
  2873.     d->rtt = rtt;
  2874.     if (abs (rtt - d->last_sent_rtt) > (d->last_sent_rtt / 8)) {
  2875.         for (l = permlinks; l; l = l->next) {
  2876.             buffer[0] = 0;
  2877.             if ((l->convection) && (l->convection->type == CT_HOST)) {
  2878.                 if (rtt)
  2879.                     sprintf (buffer, "/\377\200DEST %s %ld %s\n", name, rtt + (l->txtime + l->rxtime) / 2L, rev);
  2880.                 else
  2881.                     sprintf (buffer, "/\377\200DEST %s 0\n", name);
  2882.             }
  2883.             if (*buffer && strcmp (d->link->name, l->name)) {
  2884.                 l->convection->xmitted += usprintf (l->convection->fd, buffer);
  2885.                 d->last_sent_rtt = rtt;
  2886.             }
  2887.         }
  2888.     }
  2889. }
  2890.  
  2891.  
  2892.  
  2893. void 
  2894. h_rout_command (struct convection *cp)
  2895. {
  2896. char *dest, *user;
  2897. struct destination *d;
  2898. char buffer[2048];
  2899. int ttl;
  2900.  
  2901.     dest = getparam (cp);
  2902.     user = getparam (cp);
  2903.     ttl = atoi (getparam (cp));
  2904.     clear_locks ();
  2905.     for (d = destinations; d; d = d->next) {
  2906.         if (!strcmp (d->name, dest)) {
  2907.             sprintf (buffer, "*** route: %s -> %s -> %s (%ld)", Chostname, d->link->name, dest, d->rtt);
  2908.             send_msg_to_user ("conversd", user, buffer);
  2909.             if (ttl && strcmp (d->link->name, dest)) {
  2910.                 ttl--;
  2911.                 d->link->convection->xmitted += usprintf (d->link->convection->fd, "/\377\200ROUT %s %s %d\n", dest, user, ttl);
  2912.             }
  2913.         }
  2914.     }
  2915. }
  2916.  
  2917.  
  2918.  
  2919. void 
  2920. h_ping_command (struct convection *cp)
  2921. {
  2922. register struct permlink *pp;
  2923.  
  2924.     for (pp = permlinks; pp; pp = pp->next)
  2925.         if (pp->convection == cp) {
  2926.             cp->xmitted += usprintf (cp->fd, "/\377\200PONG %ld\n", pp->txtime);
  2927.             break;
  2928.         }
  2929. }
  2930.  
  2931.  
  2932.  
  2933. void 
  2934. h_pong_command (struct convection *cp)
  2935. {
  2936. register struct permlink *l;
  2937. time_t currtime;
  2938. long pongtime;
  2939.  
  2940.     currtime = time (&currtime);
  2941.     pongtime = atol (getparam (cp));
  2942.     for (l = permlinks; l; l = l->next)
  2943.         if (l->convection == cp) {
  2944.             l->rxtime = pongtime;
  2945.             l->txtime = max (currtime - l->testwaittime, 1);
  2946.             if (l->rxtime == 0)
  2947.                 l->rxtime = l->txtime;
  2948.             if ((abs ((int) l->rxtime) > 20001) || (abs ((int) l->txtime) > 20001)) {
  2949.                 l->rxtime = 0;
  2950.                 l->txtime = 0;
  2951.             }
  2952.             l->testnexttime = l->testwaittime + max (min (60 * (l->txtime), 7200), 120);
  2953.             /* I hacked this because of it's nasty behave - rewrite of the whole stuff is in progress */
  2954.             update_destinations (l, l->name,
  2955.                 (long) ((l->rxtime == (time_t) -1) ? l->txtime : (l->rxtime + l->txtime) / 2L), l->rev);
  2956.             break;
  2957.         }
  2958. }
  2959.  
  2960.  
  2961.  
  2962. static void
  2963. h_cmsg_command (struct convection *cp)
  2964. {
  2965. char *text, *cptr;
  2966. int channel;
  2967. char *name;
  2968.  
  2969.     name = getparam (cp);
  2970.     channel = atoi (getparam (cp));
  2971.     text = getparamline (cp);
  2972.     if (*text == '|') {
  2973.         text++;        /* skip the '|' */
  2974.         cptr = strrchr (text, '|');
  2975.         if (cptr)
  2976.             *cptr = 0;
  2977.     } else if (*(text - 1) == ' ') {
  2978.         do {
  2979.             text--;
  2980.         } while (*(text - 1) == ' ');
  2981.         text++;
  2982.     }
  2983.     /*    text[strlen(text) - 1] = 0;    */
  2984.     if (isprint (*text))
  2985.         send_msg_to_channel (name, channel, text);
  2986. }
  2987.  
  2988.  
  2989.  
  2990. /* Return 1 if the host is to be allowed, or 0 if refused - WG7J */
  2991. static int 
  2992. Allow_host (int s)
  2993. {
  2994. struct filter_link *fl;
  2995. struct sockaddr_in fsocket;
  2996. int i = sizeof (struct sockaddr_in);
  2997.  
  2998.     if (Filterlinks) {    /* Check for this ip address */
  2999.         if (getpeername (s, (char *) &fsocket, &i) != -1)    {
  3000.             for (fl = Filterlinks; fl; fl = fl->next)
  3001.                 if (fl->addr == fsocket.sin_addr.s_addr)
  3002.                     return FilterMode;
  3003.         }
  3004.         /* Not found ! */
  3005.         return !FilterMode;
  3006.     }
  3007.     return 1;
  3008. }
  3009.  
  3010.  
  3011.  
  3012. static void
  3013. h_host_command (struct convection *cp)
  3014. {
  3015. char *name, *rev, *features;
  3016. register struct convection *p;
  3017. register struct permlink *pp;
  3018. struct destination *d;
  3019.  
  3020.     if (!Allow_host (cp->fd)) {
  3021.         bye_command (cp);
  3022.         return;
  3023.     }
  3024.     name = getparam (cp);
  3025.     rev = getparam (cp);
  3026.     features = getparam (cp);
  3027.     
  3028.     (void) strlwr (rev);
  3029.     if (name[0] == '\0') {
  3030.         bye_command (cp);
  3031.         return;
  3032.     }
  3033.     if (strchr (features, 'a'))
  3034.         cp->features |= FEATURE_AWAY;
  3035.     if (strchr (features, 'd'))
  3036.         cp->features |= FEATURE_FWD;
  3037.     if (strchr (features, 'm'))
  3038.         cp->features |= FEATURE_MODES;
  3039.     if (strchr (features, 'p'))
  3040.         cp->features |= FEATURE_LINK;
  3041.     if (strchr (features, 'u'))
  3042.         cp->features |= FEATURE_UDAT;
  3043.     if (strchr (features, 'n'))
  3044.         cp->features |= FEATURE_NICK;
  3045.     /* #define DEBUG */
  3046. #ifdef DEBUG
  3047.     tcmdprintf ("Features '%s': %s%s%s%s%s%s\n", name,
  3048.         (cp->features & FEATURE_AWAY) ? "a" : "",
  3049.         (cp->features & FEATURE_FWD) ? "d" : "",
  3050.         (cp->features & FEATURE_MODES) ? "m" : "",
  3051.         (cp->features & FEATURE_LINK) ? "p" : "",
  3052.         (cp->features & FEATURE_UDAT) ? "u" : "",
  3053.         (cp->features & FEATURE_NICK) ? "n" : "");
  3054. #endif
  3055.     for (p = convections; p; p = p->next)
  3056.         if (!strcmp (p->name, name)) {
  3057.             bye_command (p);
  3058.             return;
  3059.         }
  3060.     for (pp = permlinks; pp; pp = pp->next) {
  3061.         if (!stricmp (pp->name, name) && pp->convection && pp->convection != cp) {
  3062.             bye_command ((strcmp (Chostname, name) < 0) ? pp->convection : cp);
  3063.             return;
  3064.         }
  3065.         if (!stricmp (pp->name, name) && pp->convection && pp->convection == cp)
  3066.             strncpy (pp->rev, rev, NAMELEN);
  3067.         update_destinations (pp, name, 0, rev);
  3068.     }
  3069.     if (cp->type != CT_UNKNOWN)
  3070.         return;
  3071.     cp->type = CT_HOST;
  3072.     cp->maxq = HMaxQ;
  3073.     strncpy (cp->name, name, NAMELEN);    /* already allocated */
  3074.     update_permlinks (name, cp);
  3075.     cp->xmitted += usprintf (cp->fd, hhoststr, Chostname, shortversion, myfeatures);
  3076.     for (p = convections; p; p = p->next)
  3077.         if (p->type == CT_USER) {
  3078.             cp->xmitted += usprintf (cp->fd, huserstr,
  3079.                          p->name, p->host, p->time, -1, p->channel, (p->data) ? p->data : "");
  3080.             cp->xmitted += usprintf (cp->fd, uaddstr,
  3081.                          p->name, p->host, p->nickname, p->net, (p->data) ? p->data : "~~");
  3082.         }
  3083.     for (d = destinations; d; d = d->next)
  3084.         if (d->rtt)
  3085.             cp->xmitted += usprintf (cp->fd, "/\377\200DEST %s %ld %s\n", d->name, d->rtt + 99, d->rev);
  3086. }
  3087.  
  3088.  
  3089.  
  3090. static void
  3091. h_invi_command (struct convection *cp)
  3092. {
  3093. char *fromname, *toname, *msg;
  3094. int channel;
  3095.  
  3096.     fromname = getparam (cp);
  3097.     toname = getparam (cp);
  3098.     channel = atoi (getparam (cp));
  3099.     msg = getparamline (cp);
  3100.     send_invite_msg (fromname, toname, channel, msg);
  3101. }
  3102.  
  3103.  
  3104.  
  3105. static void
  3106. h_loop_command (struct convection *cp)
  3107. {
  3108. char *host;
  3109.  
  3110.     host = getparam (cp);
  3111.     log (cp->fd, "conversd rx: LOOP %s", host);
  3112.     bye_command (cp);
  3113. }
  3114.  
  3115.  
  3116.  
  3117. /* Command to take user's personal data across a link - WG7J */
  3118. static void
  3119. h_uadd_command (struct convection *cp)
  3120. {
  3121. char *name, *host, *data, *nickname, *channel;
  3122. struct convection *p;
  3123.  
  3124.     /* do a validity check first */
  3125.     name = getparam (cp);
  3126.     host = getparam (cp);
  3127.     nickname = getparam (cp);
  3128.     channel = getparam (cp);
  3129.     data = getparam (cp);
  3130.     if (!*name || !*host || !*nickname || !*channel)
  3131.         return;
  3132.  
  3133.     if ((*data == '~' && data[1] == '~') || *data == '@')
  3134.         *data = 0;
  3135.     else
  3136.         data[strlen (data) - 1] = 0;
  3137.     /* everything seems fine, now find user ! */
  3138.     for (p = convections; p; p = p->next)
  3139.         if (!strcmp (p->name, name) && !strcmp (p->host, host)) {
  3140.             strncpy (p->nickname, nickname, NAMELEN);
  3141.             p->net = atoi (channel);
  3142.             if (strlen (data)) {
  3143.                 if (p->data)
  3144.                     free (p->data);
  3145.                 p->data = strdup (data);
  3146.             }
  3147.             break;
  3148.         }
  3149. }
  3150.  
  3151.  
  3152.  
  3153. static void
  3154. initialusers (int channel)
  3155. {
  3156. register struct convection *p;
  3157.  
  3158.     for (p = convections; p; p = p->next)
  3159.         if (p->type == CT_USER && p->channel == channel)
  3160.             p->nettime = time (&p->nettime);
  3161. }
  3162.  
  3163.  
  3164.  
  3165. /* this command simply passes on any host requests that we don't understand,
  3166.    since our neighbors MIGHT understand them */
  3167.  
  3168. void
  3169. h_unknown_command (struct convection *cp)
  3170. {
  3171. struct convection *p;
  3172.  
  3173.     for (p = convections; p; p = p->next) {
  3174.         if (p->type == CT_HOST && p != cp)
  3175.             cp->xmitted += usprintf (p->fd, cp->ibuf);
  3176.     }
  3177. }
  3178.  
  3179.  
  3180.  
  3181. /* Command to take channel topic across a link */
  3182. void
  3183. h_topi_command (struct convection *cp)
  3184. {
  3185. char *name;
  3186. int channel;
  3187.  
  3188.     (void) getparam (cp);
  3189.     (void) getparam (cp);
  3190.     (void) getparam (cp);
  3191.     channel = atoi (getparam (cp));
  3192.     name = getparamline (cp);
  3193.     rip (name);
  3194.     if (strlen (name) > TOPICLEN) {
  3195.         name[TOPICLEN] = 0;
  3196.         log (-1, "Truncated a long convers topic name");
  3197.     }
  3198.     name = strdup (name);
  3199.     sprintf (cp->ibuf, ndatstr, channel, 0, 0, 0, 0, name, "", "");
  3200.     free (name);
  3201.     setparamptr (cp, cp->ibuf);
  3202.     (void) getparam (cp);
  3203.     h_ndat_command (cp);
  3204. }
  3205.  
  3206.  
  3207.  
  3208. /* Command to take net's data across a link */
  3209. static void
  3210. h_ndat_command (struct convection *cp)
  3211. {
  3212. char *name, *moderator, *password, *cptr;
  3213. struct group *p;
  3214. int channel, private, logged, nextq, totalq, madenew = 0;
  3215.  
  3216.     channel = atoi (getparam (cp));
  3217.     private = atoi (getparam (cp));
  3218.     logged = atoi (getparam (cp));
  3219.     nextq = atoi (getparam (cp));
  3220.     totalq = atoi (getparam (cp));
  3221.  
  3222.     if (!channel && !ConvNet0)
  3223.         return;
  3224.     cptr = getparamline (cp);
  3225.     name = cptr;
  3226.     if ((moderator = strchr (name, '|')) == NULLCHAR)
  3227.         return;
  3228.     *moderator++ = '\0';
  3229.     if ((password = strchr (moderator, '|')) == NULLCHAR)
  3230.         return;
  3231.     *password++ = '\0';
  3232.     if ((cptr = strchr (password, '|')) == NULLCHAR)
  3233.         return;
  3234.     *cptr = '\0';
  3235.     /* everything seems fine, now find net ! */
  3236.     p = find_group (channel);
  3237.     if (p == NULLGROUP) {
  3238.         p = (struct group *) callocw (1, sizeof (struct group));
  3239.  
  3240.         kmutex_lock (&Group_mutex);
  3241.         p->next = groups;
  3242.         groups = p;
  3243.         kmutex_unlock (&Group_mutex);
  3244.         p->channel = channel;
  3245.         madenew = 1;
  3246.         initialusers (channel);
  3247.     }
  3248.     p->private = (char) private;
  3249.     p->logged = (char) logged;
  3250.     p->nextq = (short) nextq;
  3251.     p->totalq = (short) totalq;
  3252.     strncpy (p->name, name, TOPICLEN);
  3253.     strncpy (p->moderator, moderator, NAMELEN);
  3254.     strncpy (p->password, password, NAMELEN);
  3255.     if (private == -1) {    /* deleting net */
  3256.         cp->channel = channel;
  3257.         nonetoverride = 1;
  3258.         nonet_command (cp);
  3259.         madenew = 0;
  3260.     }
  3261.     if (madenew) {
  3262.         char buf[100];
  3263.  
  3264.         sprintf (buf, activenetstr, stars, p->name);
  3265.         send_msg_to_channel (conversd, p->channel, buf);
  3266.     }
  3267. }
  3268.  
  3269.  
  3270.  
  3271. /* Command to take net questions across a link */
  3272. static void
  3273. h_ques_command (struct convection *cp)
  3274. {
  3275. char *name, *cptr;
  3276. struct group *p;
  3277. int channel;
  3278. char type;
  3279.  
  3280.     channel = atoi (getparam (cp));
  3281.     name = getparam (cp);
  3282.     type = *name;
  3283.     name = getparam (cp);
  3284.     cptr = getparamline (cp);
  3285.  
  3286.     p = find_group (channel);
  3287.     if (p != NULLGROUP && p->qfile)
  3288.         process_question (channel, type, name, cptr);
  3289. }
  3290.  
  3291.  
  3292.  
  3293. static void
  3294. h_umsg_command (struct convection *cp)
  3295. {
  3296. char *fromname, *toname, *text;
  3297.  
  3298.     fromname = getparam (cp);
  3299.     toname = getparam (cp);
  3300.     text = getparamline (cp);
  3301.     if (*text)
  3302.         send_msg_to_user (fromname, toname, text);
  3303. }
  3304.  
  3305.  
  3306.  
  3307. static void
  3308. h_bump_command (struct convection *cp)
  3309. {
  3310. char name[NAMELEN];
  3311. char channel[NAMELEN];
  3312. register struct convection *p;
  3313.  
  3314.     strncpy (name, getparam (cp), NAMELEN);
  3315.     strncpy (channel, getparam (cp), NAMELEN);
  3316.     for (p = convections; p; p = p->next)
  3317.         if (p->type == CT_USER && !p->via && (!strcmpi (p->name, name) || !strcmpi (p->nickname, name))) {
  3318.             sprintf (p->ibuf, "/c %s", channel);
  3319.             setparamptr (cp, &cp->ibuf[3]);
  3320.             cp->locked = 0;
  3321.             channel_command (p);
  3322.             break;
  3323.         }
  3324. }
  3325.  
  3326.  
  3327.  
  3328. static void
  3329. h_user_command (struct convection *cp)
  3330. {
  3331. char *host, *name, *timestr;
  3332. char *pers;
  3333. int newchannel, oldchannel, validaddr = 0;
  3334. register struct convection *p;
  3335. time_t currtime;
  3336.  
  3337.     name = getparam (cp);
  3338.     host = getparam (cp);
  3339.     timestr = getparam (cp);
  3340.     oldchannel = atoi (getparam (cp));
  3341.     newchannel = atoi (getparam (cp));
  3342.  
  3343.     if (!*name)
  3344.         return;        /* invalid user name */
  3345.     pers = name;
  3346.     while (*pers) {
  3347.         if (!isgraph (*pers))
  3348.             return;    /* invalid user name */
  3349.         pers++;
  3350.     }
  3351.  
  3352.     if (!*host)
  3353.         return;        /* invalid host name */
  3354.  
  3355.     if (!strcmp (host, "-1"))
  3356.         return;        /* invalid host name */
  3357.  
  3358.     pers = host;
  3359.     while (*pers) {
  3360.         if (!isgraph (*pers))
  3361.             return;    /* invalid host name */
  3362.         if (!isdigit (*pers))
  3363.             validaddr++;
  3364.         pers++;
  3365.     }
  3366.     if (!validaddr)
  3367.         return;        /* invalid host name - all digits */
  3368.  
  3369.     currtime = atol (timestr);
  3370.     if (currtime == 0)
  3371.         currtime = time ((time_t *) 0);
  3372.  
  3373.     /* is this a loopback of one of our own users? */
  3374.     if (!stricmp (host, Chostname)) {
  3375.         /* try to eliminate the errant entry */
  3376.         cp->xmitted += usprintf (cp->fd, huserstr, name, host, currtime, newchannel, -1, empty);
  3377. #ifdef MAILBOX
  3378.         mail_error ("Tried to eliminate a convers loop from %s - user: '%s'", cp->name, name);
  3379. #endif
  3380.         log (-1, "Tried to eliminate a convers loop from %s - user: '%s'", cp->name, name);
  3381.         return;
  3382.     }
  3383.     pers = getparamline (cp);
  3384.     rip (pers);
  3385.  
  3386.     for (p = convections; p; p = p->next)
  3387.         if (p->type == CT_USER) {
  3388.             /* new 920705 dl9sau */
  3389.             /* If Neighbour2 registers a user on HostX, while someone has already
  3390.              * been registered for HostX via Neighbour1, then we definitely have
  3391.              * a loop !  We send a loop detect message and then close the link:
  3392.              * /..LOOP <Chostname> <myneighbour> <host>
  3393.              *
  3394.              * The LOOP PREVENTION CODE detects ONLY a loop if it starts at this
  3395.              * host. That's, why I suggest this code to be implemented in every
  3396.              * conversd implementation.
  3397.              */
  3398.             if (oldchannel < 0 && p->via != cp && !stricmp (p->host, host)) {
  3399.                 usprintf (cp->fd, loopstr, Chostname, host, (p->via) ? p->via->name : Chostname);
  3400.                 log (cp->fd, "conversd sent: LOOP %s", host);
  3401.                 bye_command (cp);
  3402.                 return;
  3403.             }
  3404.             if (p->channel == oldchannel && p->via == cp && !strcmp (p->name, name) && !strcmp (p->host, host))
  3405.                 break;
  3406.         }
  3407.     if (!p) {
  3408.         p = (struct convection *) callocw (1, sizeof (struct convection));
  3409.  
  3410.         p->type = CT_USER;
  3411.         strncpy (p->name, name, NAMELEN);
  3412.         strncpy (p->nickname, name, NAMELEN);
  3413.         strncpy (p->host, host, NAMELEN);
  3414.         p->via = cp;
  3415.         p->channel = newchannel;
  3416.         kmutex_lock (&Conv_mutex);
  3417.         p->next = convections;
  3418.         convections = p;
  3419.         kmutex_unlock (&Conv_mutex);
  3420.     }
  3421.     p->time = currtime;
  3422.     if (p->data)
  3423.         free (p->data);
  3424.     if ((*pers == '~' && pers[1] == '~') || *pers == '@')
  3425.         *pers = 0;
  3426.     p->data = strdup (pers);
  3427.     if ((p->channel = newchannel) < 0) {
  3428.         p->type = CT_CLOSED;
  3429.         free_closed_connections ();    /*  VE3DTE Apr 5/93 */
  3430.     }
  3431.     send_user_change_msg (name, host, currtime, oldchannel, newchannel, pers);
  3432. }
  3433.  
  3434.  
  3435.  
  3436. static struct group *
  3437. find_group (int channel)
  3438. {
  3439. register struct group *gp;
  3440.  
  3441.     for (gp = groups; gp; gp = gp->next)
  3442.         if (gp->channel == channel)
  3443.             return (gp);
  3444.     return (NULLGROUP);
  3445. }
  3446.  
  3447.  
  3448.  
  3449. static struct group *
  3450. get_group (struct convection *cp)
  3451. {
  3452. register struct group *gp;
  3453.  
  3454.     gp = find_group (cp->channel);
  3455.     if (gp == NULLGROUP) {
  3456.         gp = (struct group *) callocw (1, sizeof (struct group));
  3457.  
  3458.         gp->channel = cp->channel;
  3459.         strncpy (gp->moderator, cp->name, NAMELEN);
  3460.         strncpy (gp->password, cp->password, NAMELEN);
  3461.         kmutex_lock (&Group_mutex);
  3462.         gp->next = groups;
  3463.         groups = gp;
  3464.         kmutex_unlock (&Group_mutex);
  3465.         initialusers (cp->channel);
  3466.     }
  3467.     return (gp);
  3468. }
  3469.  
  3470.  
  3471.  
  3472. static struct group *
  3473. can_gcontrol (struct convection *cp)
  3474. {
  3475.     if (cp->net != cp->channel) {
  3476.         convcolorchange (cp, SYSCOLORS);
  3477.         cp->xmitted += usprintf (cp->fd, urnotstr, stars, netcontrolstr);
  3478.         return (NOCONTROL);
  3479.     }
  3480.     return (find_group (cp->channel));
  3481.  
  3482. }
  3483.  
  3484.  
  3485.  
  3486. static void
  3487. gname_command (struct convection *cp, char *cptr)
  3488. {
  3489. register struct group *gp;
  3490.  
  3491.     convcolorchange (cp, SYSCOLORS);
  3492.     gp = can_gcontrol (cp);
  3493.     if (gp == NOCONTROL || gp == NULLGROUP)
  3494.         return;
  3495.     if (*cptr) {
  3496.         char buf[100];
  3497.  
  3498.         strncpy (gp->name, cptr, 32);
  3499.         clear_locks ();
  3500.         sprintf (buf, activenetstr, stars, cptr);
  3501.         send_msg_to_channel (conversd, gp->channel, buf);
  3502.         update_net_data (gp);
  3503.     } else
  3504.         cp->xmitted += usprintf (cp->fd, activenetstr, stars, gp->name);
  3505. }
  3506.  
  3507.  
  3508.  
  3509. static void
  3510. assignnet_command (struct convection *cp)
  3511. {
  3512. register struct convection *p;
  3513. register struct group *gp;
  3514. char buf2[(NAMELEN * 2) + 2];
  3515. char *cptr;
  3516.  
  3517.     convcolorchange (cp, SYSCOLORS);
  3518.     cptr = getparamline (cp);
  3519.     if (cp->net == -1) {
  3520.         cp->xmitted += usprintf (cp->fd, urnotstr, stars, netcontrolstr);
  3521.         return;
  3522.     }
  3523.     if (!*cptr)
  3524.         cp->xmitted += usprintf (cp->fd, nouserstr, unknownstr);
  3525.     else {
  3526.         gp = find_group (cp->net);
  3527.         if (gp == NOCONTROL || gp == NULLGROUP)
  3528.             return;
  3529.         for (p = convections; p; p = p->next) {
  3530.             if (p->type == CT_USER && (!strcmpi (p->name, cptr) || !strcmpi (p->nickname, cptr)))
  3531.                 break;
  3532.         }
  3533.         if (!p) {
  3534.             cp->xmitted += usprintf (cp->fd, nouserstr, unknownstr);
  3535.             return;
  3536.         }
  3537.         if (p->net != -1)
  3538.             cp->xmitted += usprintf (cp->fd, busystr, sosorry, cptr, netcontrolstr);
  3539.         else {
  3540.             char buf[80];
  3541.  
  3542.             p->net = cp->net;
  3543.             cp->net = -1;
  3544.             strncpy (gp->moderator, p->name, NAMELEN);
  3545.             clear_locks ();
  3546.             sprintf (buf, urassigned, stars, cp->nickname, netcontrolstr, channelstr, gp->channel);
  3547.             send_msg_to_user (conversd, p->name, buf);
  3548.             getTXname (p, buf2);
  3549.             sprintf (buf, "%s'%s' is now %s\n", stars, buf2, netcontrolstr);
  3550.             if (p->net != cp->channel)
  3551.                 cp->xmitted += usprintf (cp->fd, buf);
  3552.             send_msg_to_channel (conversd, gp->channel, buf);
  3553.             update_user_data (p, 0);
  3554.             update_user_data (cp, 0);
  3555.             update_net_data (gp);
  3556.         }
  3557.     }
  3558. }
  3559.  
  3560.  
  3561.  
  3562. static void
  3563. bumpnet_command (struct convection *cp)
  3564. {
  3565. register struct convection *p, *p2;
  3566. register struct group *gp;
  3567. char *dummy;
  3568. int thischannel = 0;
  3569. char *cptr;
  3570.  
  3571.     convcolorchange (cp, SYSCOLORS);
  3572.     dummy = getparam (cp);
  3573.     cptr = getparam (cp);
  3574.     gp = can_gcontrol (cp);
  3575.     if (gp == NOCONTROL || gp == NULLGROUP)
  3576.         return;
  3577.     if (!*dummy)
  3578.         cp->xmitted += usprintf (cp->fd, nouserstr, unknownstr);
  3579.     else {
  3580.         for (p = convections; p; p = p->next) {
  3581.             if (p->type == CT_USER && (!strcmpi (p->name, dummy) || !strcmpi (p->nickname, dummy)))
  3582.                 break;
  3583.         }
  3584.         if (!p) {
  3585.             cp->xmitted += usprintf (cp->fd, nouserstr, unknownstr);
  3586.             return;
  3587.         }
  3588.         if (p->channel != cp->channel)
  3589.             cp->xmitted += usprintf (cp->fd, wrongchannel, stars, userstr, dummy, channelstr);
  3590.         else {
  3591.             thischannel = atoi (cptr);
  3592.             if (p->via) {
  3593.                 for (p2 = convections; p2; p2 = p2->next)
  3594.                     if (p2->type == CT_HOST)
  3595.                         p2->xmitted += usprintf (p2->fd, bumpstr, p->name, thischannel);
  3596.             } else {
  3597.                 sprintf (p->ibuf, "/c %d\n", thischannel);
  3598.                 setparamptr (cp, &cp->ibuf[3]);
  3599.                 cp->locked = 0;
  3600.                 channel_command (p);
  3601.             }
  3602.         }
  3603.     }
  3604. }
  3605.  
  3606.  
  3607.  
  3608. static void
  3609. process_question (
  3610. int channel,
  3611. char type,
  3612. char *name,
  3613. const char *cptr
  3614. ) {
  3615. register struct group *gp;
  3616. struct convection *p;
  3617. char buf[LINELEN], nmbuf[32], tmbuf[10], nerf[60], *ptr;
  3618. int here, sendperm = 1;
  3619. time_t currtime;
  3620.  
  3621.     gp = find_group (channel);
  3622.     if (gp == NULLGROUP)
  3623.         return;
  3624.     if (type == 'a') {
  3625.         if (!gp->totalq && !gp->qfile) {
  3626.             gp->qfile = tmpfile ();
  3627.             setbuf (gp->qfile, (char *) 0);
  3628.         }
  3629.         if (gp->qfile) {
  3630.             gp->totalq++;
  3631.             update_net_data (gp);
  3632.             sendperm = 0;
  3633.             here = ftell (gp->qfile);
  3634.             fseek (gp->qfile, 0, SEEK_END);
  3635.             currtime = time (&currtime);
  3636.             fputs (name, gp->qfile);
  3637.             fputc ('\n', gp->qfile);
  3638.             fputs (timestring (currtime), gp->qfile);
  3639.             fputc ('\n', gp->qfile);
  3640.             fputs (cptr, gp->qfile);
  3641.             fputc (0, gp->qfile);
  3642.             fseek (gp->qfile, here, SEEK_SET);
  3643.             sprintf (buf, "%s from '%s'", questionstr, name);
  3644.             send_msg_to_user (conversd, gp->moderator, buf);
  3645.         }
  3646.     } else {
  3647.         if (gp->qfile) {
  3648.             sendperm = 0;
  3649.             here = ftell (gp->qfile);
  3650.             (void) fgets (nmbuf, 16, gp->qfile);
  3651.             nmbuf[strlen (nmbuf) - 1] = 0;
  3652.             (void) fgets (tmbuf, 9, gp->qfile);
  3653.             ptr = buf;
  3654.             do {
  3655.                 *ptr = (char) fgetc (gp->qfile);
  3656.             } while (*ptr++);
  3657.             if (type == 'p') {
  3658.                 send_msg_to_user (nmbuf, gp->moderator, buf);
  3659.                 fseek (gp->qfile, here, SEEK_SET);
  3660.             } else {
  3661.                 gp->nextq++;
  3662.                 clear_locks ();
  3663.                 if (type != 's') {
  3664.                     sprintf (nerf, "%sQuestion #%-d, sent by '%s' at%s", stars, gp->nextq, nmbuf, tmbuf);
  3665.                     send_msg_to_channel (conversd, gp->channel, nerf);
  3666.                     clear_locks ();
  3667.                     send_msg_to_channel (nmbuf, gp->channel, buf);
  3668.                 } else {
  3669.                     sprintf (nerf, "%sSkipped Question #%d", stars, gp->nextq);
  3670.                     send_msg_to_user (conversd, gp->moderator, nerf);
  3671.                 }
  3672.                 update_net_data (gp);
  3673.             }
  3674.         }
  3675.     }
  3676.     if (sendperm) {        /* qfile not local, send to remote links */
  3677.         for (p = convections; p; p = p->next)
  3678.             if (p->type == CT_HOST)
  3679.                 p->xmitted += usprintf (p->fd, quesstr,
  3680.                          channel, type, name, cptr);
  3681.     }
  3682. }
  3683.  
  3684.  
  3685.  
  3686. static void
  3687. question_command (struct convection *cp, char *cptr)
  3688. {
  3689. register struct group *gp;
  3690. char type;
  3691. char buf[(NAMELEN * 2) + 2];
  3692.  
  3693.     gp = find_group (cp->channel);
  3694.     if (gp == NULLGROUP) {
  3695.         cp->xmitted += usprintf (cp->fd, nonetstr, stars);
  3696.         return;
  3697.     }
  3698.     getTXname (cp, buf);
  3699.     cp->locked = 0;
  3700.     if (cp->net != cp->channel) {    /* not net control */
  3701.         process_question (cp->channel, 'a', buf, cptr);
  3702.         cp->xmitted += usprintf (cp->fd, fullstrcr, questionstr);
  3703.     } else {        /* options only available to net control */
  3704.         if (*cptr == '?')
  3705.             cp->xmitted += usprintf (cp->fd, "%s%d questions (%d unread)\n", stars, gp->totalq, gp->totalq - gp->nextq);
  3706.         else {        /* p=preview nc only, s=skip, other=display */
  3707.             if (!gp->totalq || !(gp->totalq - gp->nextq)) {
  3708.                 cp->xmitted += usprintf (cp->fd, "%sNone\n", stars);
  3709.                 return;
  3710.             }
  3711.             type = (char) tolower (*cptr);
  3712.             if (type != 'p' && type != 's')
  3713.                 type = 'r';
  3714.             process_question (cp->channel, type, buf, cptr);
  3715.         }
  3716.     }
  3717. }
  3718.  
  3719.  
  3720.  
  3721. static void
  3722. log_command (struct convection *cp, char *cptr)
  3723. {
  3724. register struct group *gp;
  3725. int changed = 0;
  3726. time_t currtime;
  3727. char tempname[256];
  3728.  
  3729.     convcolorchange (cp, SYSCOLORS);
  3730.     currtime = time (&currtime);
  3731.     gp = can_gcontrol (cp);
  3732.     if (gp == NOCONTROL || gp == NULLGROUP)
  3733.         return;
  3734.     if (gp->logfile) {
  3735.         fprintf (gp->logfile, closeminutes, stars, timestring (currtime));
  3736.         (void) fclose (gp->logfile);
  3737.         gp->logfile = (FILE *) 0;
  3738.         gp->logged = 0;
  3739.         changed = 1;
  3740.         cp->xmitted += usprintf (cp->fd, logfilestr, stars, "clos");
  3741.     }
  3742.     if (*cptr) {
  3743.         sprintf (tempname, "%s%s%s", PublicDir, (*cptr != '/' && *cptr != '\\') ? "/" : "", cptr);
  3744.         gp->logfile = fopen (tempname, APPEND_TEXT);
  3745.         if (gp->logfile) {
  3746.             fprintf (gp->logfile, openminutes, stars, timestring (currtime), stars, gp->name, netcontrolstr, gp->moderator);
  3747.             cp->xmitted += usprintf (cp->fd, logfilestr, stars, "open");
  3748.             gp->logged = 1;
  3749.             changed = 0;
  3750.         } else
  3751.             cp->xmitted += usprintf (cp->fd, noopenstr, tempname);
  3752.     }
  3753.     if (changed)
  3754.         update_net_data (gp);
  3755.     if (gp->logged)
  3756.         glog_command (cp);
  3757. }
  3758.  
  3759.  
  3760.  
  3761. static void
  3762. nonet_command (struct convection *cp)
  3763. {
  3764. register struct group *gp, *g;
  3765.  
  3766.     gp = can_gcontrol (cp);
  3767.     if (gp == NOCONTROL || gp == NULLGROUP) {
  3768.         if (!nonetoverride)
  3769.             return;
  3770.         else {
  3771.             gp = find_group (cp->channel);
  3772.             if (gp == NULLGROUP)
  3773.                 return;
  3774.         }
  3775.     }
  3776.     if (gp->qfile)
  3777.         (void) fclose (gp->qfile);
  3778.     if (!nonetoverride) {
  3779.         log_command (cp, empty);
  3780.         gp->private = -1;    /* indicator to remotes that we're done */
  3781.         update_net_data (gp);
  3782.         clear_locks ();
  3783.         send_msg_to_channel (conversd, gp->channel, "*** Net complete!\n");
  3784.         cp->net = -1;
  3785.         update_user_data (cp, 0);
  3786.     }
  3787.     if (gp == groups)
  3788.         groups = gp->next;
  3789.     else
  3790.         for (g = groups; g; g = g->next)
  3791.             if (g->next == gp) {
  3792.                 g->next = gp->next;
  3793.                 break;
  3794.             }
  3795.     free (gp);
  3796. }
  3797.  
  3798.  
  3799.  
  3800. static void
  3801. gpassword_command (struct convection *cp, char *cptr, int disableit)
  3802. {
  3803. register struct group *gp;
  3804.  
  3805.     convcolorchange (cp, SYSCOLORS);
  3806.     gp = can_gcontrol (cp);
  3807.     if (gp == NOCONTROL || gp == NULLGROUP)
  3808.         return;
  3809.     if (disableit) {
  3810.         gp->password[0] = '\0';
  3811.         cp->xmitted += usprintf (cp->fd, net2str, stars, passwordstr, clearedstr);
  3812.         update_net_data (gp);
  3813.         return;
  3814.     }
  3815.     if (*cptr) {
  3816.         strncpy (gp->password, cptr, NAMELEN);
  3817.         cp->xmitted += usprintf (cp->fd, net2str, stars, passwordstr, "set");
  3818.         update_net_data (gp);
  3819.     } else {
  3820.         if (gp->password[0])
  3821.             cp->xmitted += usprintf (cp->fd, "%sNet %s: '%s'.\n", stars,
  3822.                 passwordstr, gp->password);
  3823.         else
  3824.             cp->xmitted += usprintf (cp->fd, "%sNo Net %s\n", stars, passwordstr);
  3825.     }
  3826. }
  3827.  
  3828.  
  3829.  
  3830. static void
  3831. gprivate_command (struct convection *cp, char *cptr)
  3832. {
  3833. struct group *gp;
  3834.  
  3835.     convcolorchange (cp, SYSCOLORS);
  3836.     gp = can_gcontrol (cp);
  3837.     if (gp != NOCONTROL && gp != NULLGROUP) {
  3838.         gp->private = (tolower (*cptr) == 'c') ? 1 : 0;
  3839.         cp->xmitted += usprintf (cp->fd, "%sNet no%s %s\n", stars,
  3840.             (gp->private) ? "w" : "t", privatestr);
  3841.         update_net_data (gp);
  3842.     }
  3843. }
  3844.  
  3845.  
  3846.  
  3847. void 
  3848. uptime_command (struct convection *cp)
  3849. {
  3850.     time_t currtime;
  3851.  
  3852.     currtime = time (&currtime);
  3853.     cp->xmitted += usprintf (cp->fd, "*** %s is up for %s\n", Chostname, ts4 (currtime - StartTime));
  3854. }
  3855.  
  3856.  
  3857.  
  3858. static void
  3859. group_command (struct convection *cp)
  3860. {
  3861. struct group *p;
  3862. int channel;
  3863.  
  3864.     convcolorchange (cp, SYSCOLORS);
  3865.     if (groups == NULLGROUP)
  3866.         cp->xmitted += usprintf (cp->fd, "%sNo Active Nets!\n", stars);
  3867.     else {
  3868.         cp->xmitted += usprintf (cp->fd, "%s  Net Topic\n", channelstr);
  3869.         for (channel = 0; channel <= MAXCHANNEL; channel++) {
  3870.             for (p = groups; p; p = p->next)
  3871.                 if (p->channel == channel)
  3872.                     cp->xmitted += usprintf (cp->fd, "%7d  %-32s %s%s%s\n", p->channel, p->name, (*p->moderator) ? "<" : "", p->moderator, (*p->moderator) ? ">" : "");
  3873.         }
  3874.         cp->xmitted += usprintf (cp->fd, trailer);
  3875.     }
  3876. }
  3877.  
  3878.  
  3879.  
  3880. static void
  3881. smiley_command (struct convection *cp)
  3882. {
  3883. int offset, k;
  3884. char buff[200];
  3885. FILE *fp;
  3886.  
  3887.     conv_randomize ();
  3888.     offset = conv_random (810, 1);
  3889.     if ((fp = fopen (SMILEYFile, "r")) == NULLFILE)
  3890.         return;
  3891.     sprintf (buff, "%sSmiley: ", stars);
  3892.     for (k = 0; k < offset; k++) {
  3893.         kwait (NULL);
  3894.         (void) fgets (&buff[12], 188, fp);
  3895.     }
  3896.     (void) fclose (fp);
  3897.     clear_locks ();
  3898.     send_msg_to_channel (conversd, cp->channel, buff);
  3899. }
  3900.  
  3901.  
  3902.  
  3903. #ifdef SAMCALLB
  3904. extern int SAMoutbytes;
  3905.  
  3906. static void
  3907. call_command (struct convection *cp)
  3908. {
  3909. char *buff;
  3910. int k;
  3911.  
  3912.     buff = getparam (cp);
  3913.     if (*buff) {
  3914.         k = cb_lookup (cp->fd, buff, (FILE *) 0);
  3915.         if (SAMoutbytes) {
  3916.             cp->xmitted += SAMoutbytes;
  3917.             if (k != 2)
  3918.                 cp->xmitted += usprintf (cp->fd, trailer);
  3919.         } else
  3920.             cp->xmitted += usprintf (cp->fd, "%sCallbook server not active at %s\n", stars, Hostname);
  3921.     } else
  3922.         cp->xmitted += usprintf (cp->fd, "%sNo callsign given\n", stars);
  3923. }
  3924. #endif
  3925.  
  3926.  
  3927.  
  3928. static void
  3929. roll_command (struct convection *cp)
  3930. {
  3931. int die1, die2;
  3932. char buff[80];
  3933. char buf[(NAMELEN * 2) + 2];
  3934.  
  3935.     conv_randomize ();
  3936.     die1 = conv_random (6, 1);
  3937.     die2 = conv_random (6, 1);
  3938.     clear_locks ();
  3939.     getTXname (cp, buf);
  3940.     sprintf (buff, rollstr, stars, buf, die1, die2, die1 + die2, trailer);
  3941.     send_msg_to_channel (conversd, cp->channel, buff);
  3942. }
  3943.  
  3944.  
  3945.  
  3946. static void
  3947. cut_command (struct convection *cp)
  3948. {
  3949. int die1, die2;
  3950. char buff[100];
  3951. char buf[(NAMELEN * 2) + 2];
  3952.  
  3953.     conv_randomize ();
  3954.     die1 = conv_random (4, 0);
  3955.     die2 = conv_random (13, 0);
  3956.     clear_locks ();
  3957.     getTXname (cp, buf);
  3958.     sprintf (buff, cutstr, stars, buf, cards[die2], suits[die1], trailer);
  3959.     send_msg_to_channel (conversd, cp->channel, buff);
  3960. }
  3961.  
  3962.  
  3963.  
  3964. static void
  3965. glog_command (struct convection *cp)
  3966. {
  3967. char buffer[75];
  3968. struct convection *p;
  3969. struct group *gp;
  3970.  
  3971.     gp = can_gcontrol (cp);
  3972.     if (gp == NOCONTROL || gp == NULLGROUP)
  3973.         return;
  3974.     clear_locks ();
  3975.     send_msg_to_channel (conversd, gp->channel, gloghdr);
  3976.     clear_locks ();
  3977.     sprintf (buffer, glogstr, userstr, nicknmstr, hoststr);
  3978.     send_msg_to_channel (conversd, gp->channel, buffer);
  3979.     for (p = convections; p; p = p->next)
  3980.         if (p->type == CT_USER && gp->channel == p->channel) {
  3981.             sprintf (buffer, "    %-8.8s %-15.15s  %s  %-30.30s\n", p->name,
  3982.                  p->nickname, timestring (p->nettime), p->host);
  3983.             clear_locks ();
  3984.             send_msg_to_channel (conversd, gp->channel, buffer);
  3985.         }
  3986.     clear_locks ();
  3987.     send_msg_to_channel (conversd, gp->channel, trailer);
  3988. }
  3989.  
  3990.  
  3991.  
  3992. static void
  3993. net_command (struct convection *cp)
  3994. {
  3995. char *cptr;
  3996. register struct group *gp;
  3997. char buf[4];
  3998. char buf2[(NAMELEN * 2) + 2];
  3999.  
  4000.     convcolorchange (cp, SYSCOLORS);
  4001.     cptr = getparam (cp);
  4002.     if (!cp->channel && !ConvNet0 && (tolower (*cptr) == 's')) {
  4003.         cp->xmitted += usprintf (cp->fd, "%sNo nets on %s 0\n", stars, channelstr);
  4004.         return;
  4005.     }
  4006.     gp = find_group (cp->channel);
  4007.     switch (tolower (*cptr)) {
  4008.         case 0:
  4009.             group_command (cp);
  4010.             break;
  4011.         case 'c':
  4012.             if (tolower (cptr[1]) == 'o') {
  4013.                 if (gp == NULLGROUP)
  4014.                     cp->xmitted += usprintf (cp->fd, nonetstr, stars);
  4015.                 else
  4016.                     cp->xmitted += usprintf (cp->fd, "%s is '%s'.\n", netcontrolstr,
  4017.                                  gp->moderator);
  4018.             } else
  4019.                 gprivate_command (cp, cptr);
  4020.             break;
  4021.         case 'r':
  4022.             if (gp == NULLGROUP)
  4023.                 cp->xmitted += usprintf (cp->fd, nonetstr, stars);
  4024.             else {
  4025.                 char new[75];
  4026.  
  4027.                 cp->xmitted += usprintf (cp->fd, fullstrcr, recheckstr);
  4028.                 getTXname (cp, buf2);
  4029.                 sprintf (new, "%s: %s", recheckstr, buf2);
  4030.                 send_msg_to_user (conversd, gp->moderator, new);
  4031.             }
  4032.             break;
  4033.         case 'o':
  4034.             gprivate_command (cp, cptr);
  4035.             break;
  4036.         case 'l':
  4037.             glog_command (cp);
  4038.             break;
  4039.         case 'i':
  4040.             if (cp->net != -1) {
  4041.                 if (cp->net != cp->channel)
  4042.                     gp = find_group (cp->net);
  4043.                 if (gp == NULLGROUP)
  4044.                     return;
  4045.                 cp->xmitted += usprintf (cp->fd, "%sYou are %s on %s %d\n", stars, netcontrolstr, channelstr, gp->channel);
  4046.                 gname_command (cp, empty);
  4047.                 cp->xmitted += usprintf (cp->fd, "%sNet is %s and the minutes are %sbeing recorded\n", stars,
  4048.                     gp->private ? "closed" : "open", gp->logged ? empty : "not ");
  4049.                 gpassword_command (cp, empty, 0);
  4050.                 sprintf (buf, "?");
  4051.                 question_command (cp, buf);
  4052.             } else
  4053.                 glog_command (cp);    /* prints my error msg */
  4054.             break;
  4055.         case 't':
  4056.             gname_command (cp, getparamline (cp));
  4057.             break;
  4058.         case 'm':
  4059.             log_command (cp, getparamline (cp));
  4060.             break;
  4061.         case 'e':
  4062.             nonet_command (cp);
  4063.             break;
  4064.         case 'a':
  4065.             assignnet_command (cp);
  4066.             break;
  4067.         case 'b':
  4068.             bumpnet_command (cp);
  4069.             break;
  4070.         case 'w':
  4071.             cptr = getparamline (cp);
  4072.             getTXname (cp, buf2);
  4073.             if (gp == NULLGROUP)
  4074.                 cp->xmitted += usprintf (cp->fd, nonetstr, stars);
  4075.             else
  4076.                 send_msg_to_user (buf2, gp->moderator, cptr);
  4077.             break;
  4078.         case 'q':
  4079.             question_command (cp, getparamline (cp));
  4080.             break;
  4081.         case '?':
  4082.         case 'h':
  4083.             strcpy (cp->ibuf, "h net");
  4084.             setparamptr (cp, &cp->ibuf[2]);
  4085.             help_command (cp);
  4086.             break;
  4087.         case 'n':
  4088.             gpassword_command (cp, getparamline (cp), 1);
  4089.             break;
  4090.         case 'p':
  4091.             gpassword_command (cp, getparamline (cp), 0);
  4092.             break;
  4093.         case 's':
  4094.             if (cp->net != -1) {
  4095.                 cp->xmitted += usprintf (cp->fd, "%sAlready a %s\n", stars, netcontrolstr);
  4096.                 return;
  4097.             }
  4098.             if (gp != NULLGROUP) {
  4099.                 cp->xmitted += usprintf (cp->fd, "%sThere's a %s\n", stars, netcontrolstr);
  4100.                 return;
  4101.             }
  4102.             gp = get_group (cp);
  4103.             cp->net = cp->channel;
  4104.             update_user_data (cp, 0);
  4105.             gname_command (cp, getparamline (cp));
  4106.             break;
  4107.         default:
  4108.             cp->xmitted += usprintf (cp->fd, unkcmdstr, unknownstr, cptr, gethelpstr);
  4109.     }
  4110.  
  4111. }
  4112.  
  4113.  
  4114.  
  4115. static struct group *
  4116. lookup_group (char *name)
  4117. {
  4118. register struct group *gp;
  4119.  
  4120.     if (name) {
  4121.         for (gp = groups; gp; gp = gp->next)
  4122.             if (!strnicmp (gp->name, name, strlen (name)))
  4123.                 return (gp);
  4124.     }
  4125.     return (NULLGROUP);
  4126. }
  4127.  
  4128.  
  4129.  
  4130. static void
  4131. list_groups_command (struct convection *cp)
  4132. {
  4133. register struct group *gp;
  4134. struct convection *p;
  4135. int cnt, channel;
  4136.  
  4137.     cp->xmitted += usprintf (cp->fd, grouphdr, stars);
  4138.     for (channel = 0; channel <= MAXCHANNEL; channel++) {
  4139.         for (gp = groups; gp; gp = gp->next) {
  4140.             if (gp->channel == channel) {
  4141.                 cnt = 0;
  4142.                 for (p = convections; p; p = p->next) {
  4143.                     if ((p->type == CT_USER) && (p->channel == gp->channel))
  4144.                         cnt++;
  4145.                 }
  4146.                 cp->xmitted += usprintf (cp->fd, "   %5d  %-34.34s  (%02d user%s  %9s  %s\n", gp->channel,
  4147.                     gp->name, cnt, (cnt > 1) ? "s)" : ") ", gp->private ? "[PRIVATE]" : empty,
  4148.                     gp->password[0] ? "[PASSWORD]" : empty);
  4149.             }
  4150.         }
  4151.     }
  4152.     cp->xmitted += usprintf (cp->fd, trailer);
  4153. }
  4154.  
  4155.  
  4156.  
  4157. static void
  4158. join_command (struct convection *cp)
  4159. {
  4160. char *s;
  4161. register struct group *gp;
  4162. int k, old;
  4163.  
  4164.     s = getparam (cp);
  4165.     if (!*s)
  4166.         return;
  4167.     if ((gp = lookup_group (s)) == NULLGROUP) {
  4168.         old = cp->channel;
  4169.         for (k = 1; k <= MAXCHANNEL; k++) {
  4170.             if ((gp = find_group (k)) == NULLGROUP)
  4171.                 break;
  4172.         }
  4173.         cp->channel = k;
  4174.         gp = get_group (cp);
  4175.         if (cp->net != -1) {
  4176.             int oldchan = cp->channel;
  4177.  
  4178.             cp->channel = cp->net;
  4179.             nonet_command (cp);
  4180.             cp->channel = oldchan;
  4181.         }
  4182.         cp->net = cp->channel;
  4183.         update_user_data (cp, 0);
  4184.         gname_command (cp, s);
  4185.         cp->channel = old;
  4186.     }
  4187.     sprintf (cp->ibuf, "/c %d", gp->channel);
  4188.     setparamptr (cp, &cp->ibuf[3]);
  4189.     channel_command (cp);
  4190. }
  4191.  
  4192.  
  4193.  
  4194. static int
  4195. gatekeeper (struct convection *cp, int channel)
  4196. {
  4197. register struct group *gp;
  4198. char buf[40];
  4199.  
  4200.     gp = find_group (channel);
  4201.     if (gp == NULLGROUP)
  4202.         return (0);    /* okay, there's no net control */
  4203.     if (cp->paged == channel) {    /* we were invited! */
  4204.         cp->paged = -1;
  4205.         return (0);
  4206.     }
  4207.     if (cp->net == channel)    /* we control the net */
  4208.         return (0);
  4209.     kwait (NULL);
  4210.     sprintf (buf, "%s'%s' tried to join", stars, cp->name);
  4211.     if (gp->private) {
  4212.         cp->xmitted += usprintf (cp->fd, sorry, sosorry, privatestr, channelstr, channel);
  4213.         send_msg_to_user (conversd, gp->moderator, buf);
  4214.         return (1);
  4215.     }
  4216.     if (gp->password[0])
  4217.         if (strcmpi (cp->password, gp->password)) {
  4218.             cp->xmitted += usprintf (cp->fd, sorry, sosorry, passwordstr, channelstr, channel);
  4219.             send_msg_to_user (conversd, gp->moderator, buf);
  4220.             return (1);
  4221.         }
  4222.     return (0);
  4223. }
  4224.  
  4225.  
  4226.  
  4227. void 
  4228. whois_command (struct convection *cp)
  4229. {
  4230. struct convection *p;
  4231. char *name;
  4232. int found = 0;
  4233.  
  4234.     name = getparam (cp);
  4235.     if (!*name)
  4236.         cp->xmitted += usprintf (cp->fd, "%sNeed username...", stars);
  4237.     else {
  4238.         for (p = convections; p; p = p->next) {
  4239.             kwait (NULL);
  4240.             if ((p->type == CT_USER) && (!stricmp (p->name, name) || !stricmp (p->nickname, name))) {
  4241.                 found = 1;
  4242.                 cp->xmitted += usprintf (cp->fd, headerstr);
  4243.                 cp->xmitted += usprintf (cp->fd, userdata,
  4244.                      p->name, p->host, (p->via) ? p->via->name : getVia (p->name),
  4245.                      p->channel, timestring (p->time), (p->data) ? p->data : empty);
  4246.                 if (strcmp (p->name, p->nickname))
  4247.                     cp->xmitted += usprintf (cp->fd, "\n      Nickname: %s", p->nickname);
  4248.                 if (p->data && strcmp (p->data, "@"))
  4249.                     cp->xmitted += usprintf (cp->fd, "\n      Personal: %s", p->data);
  4250.                 cp->xmitted += usprintf (cp->fd, "\n       Channel: %d", p->channel);
  4251.                 break;
  4252.             }
  4253.         }        /* for convections */
  4254.         if (!found)
  4255.             cp->xmitted += usprintf (cp->fd, "%sUser not found...", stars);
  4256.     }
  4257.     cp->xmitted += usprintf (cp->fd, "\n%s", trailer);
  4258. }
  4259.  
  4260.  
  4261.  
  4262. void 
  4263. sysinfo_command (struct convection *cp)
  4264. {
  4265. char host[NAMELEN + 1];
  4266.  
  4267.     strncpy (host, getparam (cp), NAMELEN);
  4268.     if (!*host || !stricmp (host, Chostname) || !stricmp (host, "all")) {
  4269.         cp->xmitted += usprintf (cp->fd, sysinfoheader, stars, Chostname, Hostname);
  4270.         cp->xmitted += usprintf (cp->fd, "%s%s: %s\n", stars, Chostname, (mysysinfo) ? mysysinfo : noinfo);
  4271.         if (stricmp (host, "all"))
  4272.             return;
  4273.     }
  4274.     sprintf (cp->ibuf, "/\377\200SYSI %s %s\n", cp->name, host);
  4275.     h_unknown_command (cp);
  4276. }
  4277.  
  4278.  
  4279.  
  4280. void 
  4281. h_sysi_command (struct convection *cp)
  4282. {
  4283. char user[NAMELEN + 1], host[NAMELEN + 1];
  4284. char buffer[256];
  4285.  
  4286.     strncpy (user, getparam (cp), NAMELEN);
  4287.     strncpy (host, getparam (cp), NAMELEN);
  4288.     cp->locked = 0;
  4289.  
  4290.     if (!stricmp (host, Chostname) || !stricmp (host, "all")) {    /* if for us */
  4291.         sprintf (buffer, sysinfoheader, stars, Chostname, Hostname);
  4292.         send_msg_to_user ("conversd", user, buffer);
  4293.         clear_locks ();
  4294.         sprintf (buffer, "%s%s: %s\n", stars, Chostname, (mysysinfo) ? mysysinfo : noinfo);
  4295.         send_msg_to_user ("conversd", user, buffer);
  4296.         if (stricmp (host, "all"))
  4297.             return;
  4298.     }
  4299.     /* else, pass it on */
  4300.     sprintf (cp->ibuf, "/\377\200SYSI %s %s\n", user, host);
  4301.     h_unknown_command (cp);
  4302. }
  4303.  
  4304.  
  4305.  
  4306. #ifdef TESTTPP
  4307. void 
  4308. test1_command (struct convection *cp)
  4309. {
  4310.     sprintf (cp->ibuf, "/\377\200ECMD conversd test3\n");
  4311.     h_unknown_command (cp);
  4312. }
  4313.  
  4314.  
  4315.  
  4316. void 
  4317. test2_command (struct convection *cp)
  4318. {
  4319.     sprintf (cp->ibuf, "/\377\200ECMD %s ecmdtest\n", cp->name);
  4320.     h_unknown_command (cp);
  4321. }
  4322.  
  4323.  
  4324.  
  4325. void 
  4326. test3_command (struct convection *cp)
  4327. {
  4328.     clear_locks ();
  4329.     send_msg_to_channel (conversd, 6809, "Test3 command executed\n");
  4330. }
  4331. #endif
  4332.  
  4333.  
  4334.  
  4335. #if 0
  4336. static void
  4337. conv_usflush (int s)
  4338. {
  4339. register struct usock *up;
  4340.  
  4341.     if ((up = itop (s)) == NULLUSOCK)
  4342.         return;
  4343.  
  4344.     if (up->obuf == NULLBUF)
  4345.         return;
  4346.     if (len_p (up->obuf) < 2400)
  4347.         return;
  4348.     usflush (s);
  4349. }
  4350. #endif
  4351.  
  4352.  
  4353.  
  4354. static struct cmdtable {
  4355.     const char *name;
  4356.     void (*fnc) (struct convection *);
  4357.     int states;
  4358. } cmdtable[] = {
  4359.     { "?",            cmdsummary_command,    CM_USER },
  4360.     { "accept",        accept_command,        CM_USER },
  4361.     { "action",        me_command,        CM_USER },
  4362.     { "bye",        bye_command,        CM_USER },
  4363.     { "beep",        sounds_command,        CM_USER },
  4364.     { "bell",        sounds_command,        CM_USER },
  4365.     { "channel",        channel_command,    CM_USER },
  4366. #ifdef SAMCALLB
  4367.     { "call",        call_command,        CM_USER },
  4368. #endif
  4369.     { "color",        color_command,        CM_USER },
  4370. #ifdef LZW
  4371.     { "compressed",        compressed_command,    CM_USER },
  4372. #endif
  4373.     { "cq",            cq_command,        CM_USER },
  4374.     { "cstat",        cstat_command,        CM_USER },
  4375.     { "cut",        cut_command,        CM_USER },
  4376.     { "destinations",    hosts_command,        CM_USER },
  4377.     { "exit",        bye_command,        CM_USER },
  4378.     { "exclude",        imsg_command,        CM_USER },
  4379.     { "groups",        list_groups_command,    CM_USER },
  4380.     { "help",        help_command,        CM_USER },
  4381.     { "hosts",        hosts_command,        CM_USER },
  4382.     { "invite",        invite_command,        CM_USER },
  4383.     { "imsg",        imsg_command,        CM_USER },
  4384.     { "iwrite",        imsg_command,        CM_USER },
  4385.     { "join",        join_command,        CM_USER },
  4386.     { "links",        links_command,        CM_USER },
  4387.     { "list",        list_command,        CM_USER },
  4388.     { "msg",        msg_command,        CM_USER },
  4389.     { "me",            me_command,        CM_USER },
  4390.     { "name",        name_command,        CM_UNKNOWN },
  4391.     { "net",        net_command,        CM_USER },
  4392.     { "news",        news_command,        CM_USER },
  4393.     { "nickname",        nickname_command,    CM_USER },
  4394.     { "nonickname",        nickname_command,    CM_USER },
  4395.     { "nopassword",        password_command,    CM_USER },
  4396.     { "note",        personal_command,    CM_USER },
  4397.     { "page",        invite_command,        CM_USER },
  4398.     { "password",        password_command,    CM_USER },
  4399.     { "personal",        personal_command,    CM_USER },
  4400.     { "quit",        bye_command,        CM_USER },
  4401. #ifdef ALLSERV
  4402.     { "quote",        quote_command,        CM_USER },
  4403. #endif
  4404.     { "realname",        realname_command,    CM_USER },
  4405.     { "roll",        roll_command,        CM_USER },
  4406.     { "send",        msg_command,        CM_USER },
  4407.     { "smiley",        smiley_command,        CM_USER },
  4408.     { "sounds",        sounds_command,        CM_USER },
  4409.     { "sysinfo",        sysinfo_command,    CM_USER },
  4410. #ifdef TESTTPP
  4411.     { "test1",        test1_command,        CM_USER },
  4412.     { "test2",        test2_command,        CM_USER },
  4413.     { "test3",        test3_command,        CM_USER },
  4414. #endif
  4415.     { "time",        time_command,        CM_USER },
  4416.     { "uptime",        uptime_command,        CM_USER },
  4417.     { "users",        who_command,        CM_USER },
  4418.     { "version",        version_command,    CM_USER },
  4419.     { "who",        who_command,        CM_USER },
  4420.     { "whois",        whois_command,        CM_USER },
  4421.     { "write",        msg_command,        CM_USER },
  4422.  
  4423.     { "\377\200bump",    h_bump_command,        CM_HOST },
  4424.     { "\377\200cmsg",    h_cmsg_command,        CM_HOST },
  4425.     { "\377\200dest",    h_dest_command,        CM_HOST },
  4426.     { "\377\200ecmd",    h_ecmd_command,        CM_HOST },
  4427.     { "\377\200host",    h_host_command,        CM_UNKNOWN },
  4428.     { "\377\200invi",    h_invi_command,        CM_HOST },
  4429.     { "\377\200link",    h_link_command,        CM_HOST },
  4430.     { "\377\200loop",    h_loop_command,        CM_HOST },
  4431.     { "\377\200ndat",    h_ndat_command,        CM_HOST },
  4432.     { "\377\200ping",    h_ping_command,        CM_HOST },
  4433.     { "\377\200pong",    h_pong_command,        CM_HOST },
  4434.     { "\377\200ques",    h_ques_command,        CM_HOST },
  4435.     { "\377\200rout",    h_rout_command,        CM_HOST },
  4436.     { "\377\200sysi",    h_sysi_command,        CM_HOST },
  4437.     { "\377\200topi",    h_topi_command,        CM_HOST },
  4438.     { "\377\200uadd",    h_uadd_command,        CM_HOST },
  4439.     { "\377\200umsg",    h_umsg_command,        CM_HOST },
  4440.     { "\377\200user",    h_user_command,        CM_HOST },
  4441.     { NULLCHAR,        0,            0 }
  4442. };
  4443.  
  4444.  
  4445.  
  4446. static void
  4447. process_commands (struct convection *cp, struct mbx *m)
  4448. {
  4449. char *arg;
  4450. int arglen, size;
  4451. int firstcmd = 1;
  4452. char *ccp, *params;
  4453. struct cmdtable *cmdp;
  4454. char buf[(NAMELEN * 2) + 2];
  4455. int prevblock;
  4456.  
  4457.     Conflogins++;
  4458. #ifdef STATS_USE
  4459.     localConfUsers++;
  4460.     STATS_adduse (1);
  4461. #endif
  4462. #ifdef XSERVER
  4463.     xnotify (X_CONF);
  4464. #endif
  4465.     if (m)
  4466.         firstcmd = 0;
  4467.     if (m == (struct mbx *) 1)
  4468.         m = NULLMBX;
  4469.     if (confMOTD != NULL && !cp->features)
  4470.         cp->xmitted += usprintf (cp->fd, "\n%s\n", confMOTD);
  4471.     for (;;) {
  4472.           loop:
  4473. #ifdef MBXTDISC
  4474.         if (m)        /* Restart the inactivity timer - WG7J */
  4475.             start_timer (&m->tdisc);
  4476. #endif
  4477. #if 0
  4478.         conv_usflush (cp->fd);
  4479. #else
  4480.         usflush (cp->fd);    /* might not be neccesary */
  4481. #endif
  4482. #if 1
  4483.         (void) setflush (cp->fd, '\n');    /* automatic flushing each line */
  4484. #endif
  4485.         kwait (NULL);
  4486.         if (cp->type == CT_CLOSED)
  4487.             break;
  4488.         memset (cp->ibuf, 0, INBUFLEN);
  4489.         prevblock = getblock (cp->fd);
  4490.         (void) sockblock (cp->fd, prevblock & ~SOCK_NORXBLOCK);
  4491.         if ((size = recvline (cp->fd, (unsigned char *) cp->ibuf, INBUFLEN)) <= 0)
  4492.             break;
  4493. #if 0
  4494.         sockblock (cp->fd, prevblock);
  4495. #endif
  4496.         if (size == (INBUFLEN))
  4497.             log (-1, "maximum sized convers line received");
  4498. #if 1
  4499.         usflush (cp->fd);    /* might not be neccesary */
  4500.         (void) setflush (cp->fd, -1);    /* let command output queue */
  4501. #endif
  4502.         cp->received += size;
  4503.         clear_locks ();
  4504.         cp->locked = 1;
  4505.         if (*cp->ibuf == '/') {
  4506.             setparamptr (cp, &cp->ibuf[1]);
  4507.             arg = getparam (cp);
  4508.             arglen = (int) strlen (arg);
  4509.             for (cmdp = cmdtable; cmdp->name; cmdp++) {
  4510.                 if (!strncmpi (cmdp->name, arg, (unsigned int) arglen)) {
  4511.                     if (cmdp->states & (1 << cp->type)) {
  4512.                         (*cmdp->fnc) (cp);
  4513.                         if (cp->type != CT_UNKNOWN)
  4514.                             firstcmd = 0;
  4515.                     }
  4516.                     if (firstcmd)
  4517.                         cp->xmitted += usprintf (cp->fd, namecmdstr, stars);
  4518.                     goto loop;
  4519.                 }
  4520.             }
  4521.             /* didn't find match in table - see if it is a host command */
  4522.             if (uchar(cp->ibuf[1]) == uchar('\377') && uchar(cp->ibuf[2]) == uchar('\200')) {    /*lint !e743 */
  4523.                 if (*(cp->ibufpt))
  4524.                     *(cp->ibufpt - 1) = ' ';
  4525.                 h_unknown_command (cp);    /* yep, pass it on */
  4526.                 goto loop;
  4527.             }
  4528.             if (firstcmd)
  4529.                 cp->xmitted += usprintf (cp->fd, namecmdstr, stars);
  4530.             else if (cp->type == CT_USER) {
  4531.                 if (!ecmd_exists (arg))
  4532.                     cp->xmitted += usprintf (cp->fd, unkcmdstr, unknownstr, arg, gethelpstr);
  4533.                 else {
  4534.                     char buff[INBUFLEN];
  4535.  
  4536.                     params = getparamline(cp);
  4537.                     sprintf (buff, "/\377\200ECMD %s %s %s\n", cp->name, arg, params);
  4538.                     strncpy (cp->ibuf, buff, INBUFLEN);
  4539.                     h_unknown_command (cp);
  4540.                 }
  4541.             }
  4542.             goto loop;
  4543.         }
  4544.         if (firstcmd) {
  4545.             /* only before a valid user */
  4546.             if (!cp->features)    /* not a pending host link */
  4547.                 cp->xmitted += usprintf (cp->fd, namecmdstr, stars);
  4548.             goto loop;
  4549.         }
  4550. #ifndef TNOS_68K
  4551.         if ((ccp = strpbrk (cp->ibuf, "\r\n")) != NULLCHAR)
  4552. #else
  4553.         if ((ccp = strpbrk (cp->ibuf, "\r\l")) != NULLCHAR)
  4554. #endif
  4555.             *ccp = '\0';
  4556. #ifdef NOCTLCHARS
  4557.         if (isprint (cp->ibuf[0]) != 0 && cp->type == CT_USER) {
  4558. #else
  4559.         if (cp->type == CT_USER) {
  4560. #endif
  4561.             getTXname (cp, buf);
  4562.             send_msg_to_channel (buf, cp->channel, cp->ibuf);
  4563.         }
  4564.     }
  4565.     (void) sockblock (cp->fd, SOCK_BLOCK);
  4566.     if (m)
  4567.         (void) setflush (cp->fd, -1);
  4568. #ifdef STATS_USE
  4569.     localConfUsers--;
  4570. #endif
  4571. #ifdef XSERVER
  4572.     xnotify (X_CONF);
  4573. #endif
  4574.     bye_command (cp);
  4575.     free_closed_connections ();
  4576. }
  4577.  
  4578.  
  4579.  
  4580. /* Incoming convers session */
  4581. void
  4582. conv_incom (int s, void *t OPTIONAL, void *p OPTIONAL)
  4583. {
  4584. struct convection *cp;
  4585. struct sockaddr fsocket;
  4586. int trans, i = SOCKSIZE;
  4587. char *cptr, *cptr2;
  4588.  
  4589.     (void) sockowner (s, Curproc);    /* We own it now */
  4590.     (void) sockmode (s, SOCK_ASCII);
  4591.     (void) sockblock (s, SOCK_NOTXBLOCK);    /* prevent backlogs ! */
  4592.     cp = alloc_connection (s);
  4593.  
  4594.     if (strncmp (Curproc->name, "permlink: ", 10))    {
  4595.         trans = DTranslate;
  4596.         DTranslate = 0;        /* force output to be numeric IP addr */
  4597.         if (getpeername (s, (char *) &fsocket, &i) != -1)    {
  4598.             cptr = psocket (&fsocket);
  4599.             DTranslate = trans;    /* Restore original state */
  4600.             if ((cptr2 = strchr (cptr, ':')) != NULLCHAR)
  4601.                 *cptr2 = 0;
  4602.             sprintf (cp->ibuf, "conversd: from %s", cptr);
  4603.         } else
  4604.             sprintf (cp->ibuf, "conversd: from (unknown host)");
  4605.         chname (Curproc, cp->ibuf);
  4606.     }
  4607.  
  4608.     cp->channel = CChannel;
  4609.     statlog ("CONFERENCE - New Telnet User");
  4610.     {
  4611.         struct permlink *pl;
  4612.  
  4613.         for (pl = permlinks; pl; pl = pl->next) {
  4614.             if (pl->fd == s) {
  4615.                 pl->convection = cp;
  4616.                 cp->xmitted += usprintf (s, hhoststr, Chostname, shortversion, myfeatures);
  4617.                 cp->features = 1;    /* to suppress error msgs */
  4618.                 break;
  4619.             }
  4620.         }
  4621.  
  4622.         if (pl == NULLPERMLINK) {
  4623.             cp->xmitted += usprintf (cp->fd,
  4624.                "%s%s %s", conferencestr, Chostname, gethelpstr);
  4625.             if (ConvHeader)
  4626.                 usprintf (cp->fd, namecmdstr, stars);
  4627.         }
  4628.     }
  4629.     process_commands (cp, (struct mbx *) 0);
  4630. }
  4631.  
  4632.  
  4633.  
  4634. #ifdef MAILBOX
  4635. /* this is for Mailbox users */
  4636. void
  4637. mbox_converse (int fd, char *name, int channel, struct mbx *mbox)
  4638. {
  4639. struct convection *cp;
  4640. char *oldprocname;
  4641.  
  4642.     if (Sconv == -1)
  4643.         return;
  4644.     oldprocname = strdup (Curproc->name);
  4645.     (void) sockblock (fd, SOCK_NOTXBLOCK);    /* prevent backlogs ! */
  4646.     cp = alloc_connection (fd);
  4647.     sprintf (cp->ibuf, "convers: user '%s'", name);
  4648.     chname (Curproc, cp->ibuf);
  4649.     cp->ibuf[0] = 0;
  4650.     cp->channel = (channel == -1) ? CChannel : channel;
  4651.     strncpy (cp->name, name, NAMELEN);
  4652.     strncpy (cp->nickname, cp->name, NAMELEN);
  4653.     strncpy (cp->host, Chostname, NAMELEN);
  4654.     cp->type = CT_USER;
  4655.     cp->flags &= ~CLOSE_SOCK;    /* do not close socket on exit */
  4656. #if 0
  4657.     setflush (fd, '\n');    /* automatic flushing each line */
  4658. #endif
  4659.     cp->xmitted += usprintf (fd, "%s%s %s", conferencestr, Chostname, gethelpstr);
  4660.     announce_new_user (cp);
  4661.     set_personal (cp);
  4662.     clear_locks ();
  4663.     cp->locked = 1;        /* send to everyone but ourself */
  4664.     mystatus (cp, (int) -1);
  4665.     process_commands (cp, (mbox) ? mbox : (struct mbx *) 1);
  4666.     chname (Curproc, oldprocname);
  4667. }
  4668. #endif /* MAILBOX */
  4669.  
  4670.  
  4671.  
  4672. void 
  4673. conversWriteall (char *str)
  4674. {
  4675. struct convection *p;
  4676.  
  4677.     for (p = convections; p; p = p->next)
  4678.         if (p->type == CT_USER) {
  4679.             p->xmitted += usprintf (p->fd, "%s SYSOP: %s\n", amessage, str);
  4680.             usflush (p->fd);
  4681.         }
  4682. }
  4683.  
  4684.  
  4685.  
  4686. void 
  4687. conversWrite (char *str, char *user)
  4688. {
  4689. struct convection *p;
  4690.  
  4691.     for (p = convections; p; p = p->next)
  4692.         if ((p->type == CT_USER) && !stricmp (p->name, user)) {
  4693.             p->xmitted += usprintf (p->fd, "%s SYSOP: %s\n", amessage, str);
  4694.             usflush (p->fd);
  4695.         }
  4696. }
  4697.  
  4698.  
  4699.  
  4700. static void
  4701. convcolorchange (struct convection *p OPTIONAL, char *str OPTIONAL)
  4702. {
  4703. #ifndef UNIX
  4704.     int old;
  4705.  
  4706.     if (p->flags & USE_COLOR) {
  4707.         old = Curproc->output;
  4708.         Curproc->output = p->fd;
  4709.         p->xmitted += colorchange (str, p->colorset);
  4710.         Curproc->output = old;
  4711.     }
  4712. #endif
  4713. }
  4714.  
  4715.  
  4716.  
  4717. static void
  4718. cmdsummary_command (struct convection *cp)
  4719. {
  4720. int i;
  4721. char buf[82];
  4722. struct cmdtable *cmdp = cmdtable;
  4723. int width = 13, count = 6;
  4724. struct extendedcmds *ecmdp;
  4725.  
  4726.     cp->xmitted += usprintf (cp->fd, summary, stars);
  4727.     memset (buf, ' ', sizeof (buf));
  4728.     buf[77] = '\n';
  4729.     buf[78] = '\0';
  4730.     for (i = 0; cmdp->name; cmdp++, i = ((i + 1) % count)) {
  4731.         if ((unsigned char) *cmdp->name == 255)
  4732.             break;
  4733.         strncpy (&buf[i * width], cmdp->name, strlen (cmdp->name));
  4734.         if (i == (count - 1)) {
  4735.             cp->xmitted = usprintf (cp->fd, "%s ", buf);
  4736.             memset (buf, ' ', 77);
  4737.         }
  4738.     }
  4739.     if (i)
  4740.         cp->xmitted += usprintf (cp->fd, buf);
  4741.  
  4742.     if (ecmds != NULLEXTCMD && ecmds->name) {
  4743.         ecmdp = ecmds;
  4744.         memset (buf, ' ', sizeof (buf));
  4745.         buf[77] = '\n';
  4746.         buf[78] = '\0';
  4747.         cp->xmitted += usprintf (cp->fd, extendedsummary, stars);
  4748.         for (i = 0; ecmdp && ecmdp->name; ecmdp = ecmdp->next, i = ((i + 1) % count)) {
  4749.             strncpy (&buf[i * width], ecmdp->name, strlen (ecmdp->name));
  4750.             if (i == (count - 1)) {
  4751.                 cp->xmitted += usprintf (cp->fd, "%s ", buf);
  4752.                 memset (buf, ' ', 77);
  4753.             }
  4754.         }
  4755.         if (i)
  4756.             cp->xmitted += usprintf (cp->fd, buf);
  4757.     }
  4758.     cp->xmitted += usprintf (cp->fd, trailer);
  4759. }
  4760.  
  4761.  
  4762.  
  4763. static void
  4764. h_ecmd_command (struct convection *cp)
  4765. {
  4766. struct cmdtable *cmdp;
  4767. char arg[64], user[NAMELEN + 1], params[INBUFLEN + 1];
  4768. struct convection *usercp;
  4769. int arglen, addedbuf = 0;
  4770. struct extendedcmds *eadd;
  4771.  
  4772.     strncpy (user, getparam (cp), NAMELEN);
  4773.     strncpy (arg, getparam (cp), 64);
  4774.     arglen = (int) strlen (arg);
  4775.     strncpy (params, getparamline (cp), INBUFLEN);
  4776.  
  4777.     if (!stricmp (user, conversd)) {    /* adding a new command */
  4778.         if (!ecmd_exists (arg)) {
  4779.             eadd = mallocw (sizeof (struct extendedcmds));
  4780.  
  4781.             eadd->next = ecmds;
  4782.             eadd->name = strdup(arg);
  4783.             ecmds = eadd;
  4784.         }
  4785.         sprintf (cp->ibuf, "/\377\200ECMD conversd %s\n", arg);
  4786.         h_unknown_command (cp);
  4787.         return;
  4788.     }
  4789.     /* find the actual user who sent the command */
  4790.     for (usercp = convections; usercp; usercp = usercp->next) {
  4791.         if (!stricmp (usercp->name, user))
  4792.             break;
  4793.     }
  4794.     if (usercp == NULLCONNECTION)
  4795.         return;
  4796.  
  4797.     /* now lookup the command locally */
  4798.     for (cmdp = cmdtable; cmdp->name; cmdp++)
  4799.         if (!strncmp (cmdp->name, arg, (unsigned) arglen)) {
  4800.             if (cmdp->states & (1 << usercp->type)) {
  4801.                 if (!usercp->ibuf) {
  4802.                     addedbuf = 1;
  4803.                     usercp->ibuf = (char *) callocw (1, INBUFLEN + 1);
  4804.                 }
  4805.                 sprintf (usercp->ibuf, "%s %s\n", arg, params);
  4806.                 (*cmdp->fnc) (usercp);
  4807.                 if (addedbuf)
  4808.                     free (usercp->ibuf);
  4809.             }
  4810.             return;
  4811.         }
  4812.     /* if not found locally, then send it on to others */
  4813.     sprintf (cp->ibuf, "/\377\200ECMD %s %s %s\n", user, arg, params);
  4814.     h_unknown_command (cp);
  4815. }
  4816.  
  4817.  
  4818. static long seed = 1L;
  4819.  
  4820. #define CONV_RAND_MAX 0x7fffffff
  4821.  
  4822. static int
  4823. conv_rand (void)
  4824. {
  4825.     seed = (1103515245L * seed + 12345) & CONV_RAND_MAX;
  4826.     return ((int) (seed & 077777));
  4827. }
  4828.  
  4829.  
  4830.  
  4831. static void
  4832. conv_randomize (void)
  4833. {
  4834.     seed = (time (0) & CONV_RAND_MAX);
  4835. }
  4836.  
  4837.  
  4838.  
  4839. static int
  4840. conv_random (int num, int base)
  4841. {
  4842.     return (((long) conv_rand () % num) + base);
  4843. }
  4844.  
  4845.  
  4846. #endif /* CONVERS */
  4847.  
  4848.